2013-05-16 4 views
30

Как я могу объявить класс шаблона (адаптер) с различными контейнерами в качестве аргументов шаблона? Например, мне нужно объявить класс:Шаблон класса с контейнером шаблона

template<typename T, typename Container> 
class MyMultibyteString 
{ 
    Container buffer; 
    ... 
}; 

И я хочу это к моему на основе вектора. Как сделать его жестким? (чтобы кто-то не мог написать такое заявление MyMultibyteString<int, vector<char>>).

Кроме того, как реализовать такую ​​конструкцию:

MyMultibyteString<int, std::vector> mbs; 

без прохождения аргумента шаблона в контейнер.

ответ

59

Вы должны использовать параметры шаблона шаблона:

template<typename T, template <typename, typename> class Container> 
//     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
class MyMultibyteString 
{ 
    Container<T, std::allocator<T>> buffer; 
    // ... 
}; 

Это позволит вам написать:

MyMultibyteString<int, std::vector> mbs; 

Вот компиляции live example. Альтернативный способ написания выше, может быть:

template<typename T, 
    template <typename, typename = std::allocator<T>> class Container> 
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
class MyMultibyteString 
{ 
    Container<T> buffer; // <== No more need to specify the second argument here 
    // ... 
}; 

А вот соответствующий live example.

Единственное, на что вы должны обратить внимание, это то, что количество и тип аргументов в объявлении параметра шаблона шаблона должны точно соответствовать количеству и типу аргументов в определении соответствующего шаблона класса, который вы хотите передать как шаблон, независимо от того, что некоторые из этих параметров могут иметь значения по умолчанию.

Например, the class template std::vector accepts two template parameters (тип элемента и тип распределителя), хотя второй имеет значение по умолчанию std::allocator<T>. Из-за этого, вы можете не запись:

template<typename T, template <typename> class Container> 
//        ^^^^^^^^ 
//        Notice: just one template parameter declared! 
class MyMultibyteString 
{ 
    Container<T> buffer; 
    // ... 
}; 

// ... 

MyMultibyteString<int, std::vector> mbs; // ERROR! 
//      ^^^^^^^^^^^ 
//      The std::vector class template accepts *two* 
//      template parameters (even though the second 
//      one has a default argument) 

Это означает, что вы не будете в состоянии написать один шаблон одного класса, который может принимать как std::set и std::vector в качестве параметра шаблона шаблон, потому что в отличие от std::vector, the std::set class template accepts three template parameters.

+0

Какой большой, основательный ответ. –

+0

@ScottJones: Рад, что вы сочли это полезным :) –

+3

@ScottJones Что касается вашего утверждения: 'Это означает, что вы не сможете написать один шаблон шаблона, который может принимать как std :: set, так и std :: vector': Would вариативные шаблоны решают проблему? http://stackoverflow.com/a/20499809/2436175 – Antonio

2

Другой подход для решения этой проблемы является использование VARIADIC шаблонов и что вы можете использовать любой контейнер, как это было предложено в комментариях выше, и вот реализации внешних:

template<template <typename... Args> class Container,typename... Types> 
class Test 
{ 
    public: 
    Container<Types...> test; 

}; 
int main() 
{ 
    Test<std::vector,int> t; 
    Test<std::set,std::string> p; 
    return 0; 
} 
Смежные вопросы