Подтвердить что ты не робот

Класс шаблона с контейнером шаблона

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

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

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

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

MyMultibyteString<int, std::vector> mbs;

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

4b9b3361

Ответ 1

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

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

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

MyMultibyteString<int, std::vector> mbs;

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

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
    // ...
};

И вот соответствующий живой пример.

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

Например, шаблон шаблона std::vector принимает два параметра шаблона (тип элемента и тип распределителя), хотя второй имеет значение по умолчанию 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, шаблон класса std::set принимает три параметра шаблона.

Ответ 2

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

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;
}