我试图通过实现通用容器类来理解C ++模板模板。这是代码:
using namespace std;
template <typename T, template <typename STORETYPE> class Container>
class Store {
public:
~Store() {};
Store() {};
void someFunc( const T & ) {};
//...
private:
Container<T> storage;
};
int main(int argc, char *argv[])
{
Store<int,deque> myStore; // error here, won't compile!
}
上面的代码生成编译器错误消息。错误消息是:
“模板模板参数具有与其对应的模板模板参数不同的模板参数 存储aStack1;
我不知道为什么。怎么了?
答案 0 :(得分:6)
您的问题是std::deque
(以及其他标准容器)并不只是采用单个模板参数。除了存储类型,您还可以指定要使用的分配器仿函数类型。
如果您不关心这些额外的参数,您可以采用可变参数模板模板并继续前进:
template <typename T, template <typename...> class Container>
// variadic ^^^
class Store {
如果您还想支持将可选参数传递给容器类型,可以像这样转发它们:
template <template <typename ...> class Container, typename T, typename... ContainerArgs>
class Store {
//...
Container<T,ContainerArgs...> storage;
};
然后像这样实例化:
Store<deque,int> myStore;
Store<deque,int,MyIntAllocator> mySpecialStore;
但是,您可能只想使用特化提取模板参数:
template <typename Container>
class Store;
template <template <typename...> class ContainerType, typename T, typename... OtherArgs>
class Store<ContainerType<T,OtherArgs...>>
{
//...
};
这将允许客户端代码实例化如下:
Store<deque<int>> myStore;
Store<deque<int,MyIntAllocator>> mySpecialStore;
Store<T> myOtherStore; //where T is some specialized container type
答案 1 :(得分:1)
std::deque
定义为
template <class T, class Allocator = allocator<T> > class deque;
因此,您应该将Store
的定义更改为匹配:
template <typename T, template <typename...> class Container>
class Store {
但实际上你甚至不需要模板模板参数。只需将容器类型作为参数传递即可实现更加通用,因此例如Storage
甚至可以支持std::map
:
template <typename Container>
class Store {
public:
using value_type = typename Container::value_type;
~Store() {};
Store() {};
void someFunc( const value_type& ) {};
//...
private:
Container storage;
};
Store<std::map<int, float>> myStore;
答案 2 :(得分:1)
作为@TartanLlama答案的替代方案,您还可以使用deque
的别名。
template<typename T>
using deque_alias = deque<T>;
int main(int argc, char *argv[])
{
Store<int,deque_alias> myStore; // now it will compile!
}
然后也正确使用默认模板参数(此处为std::allocator<T>
)。 (像MSVC这样的编译器有问题,否则会失败,因为他们期望有两个模板参数,例如参见here。)