目录 Table of Contents
template template parameter 模板模板参数
模板模板参数
我现在设计了一个 template, 里面的第二个模板参数, 这个模板参数本身又是一个 template
这个语法应该怎么写呢, 就是下面注释的这一块
template<typename T,
template<typename T> // 第二个模板参数, 本身又是一个模板
class Container>
>
class XCls
{
private:
Container<T> c;
public:
//...
};
只有在模板尖括号里面, typename
和 class
共通, 其它地方都不可以
这个 Container 在这里也只是一个符号而已, 叫什么都无所谓
这个 Container 类是拿第一个模板参数来作为自己的参数
既然设计成这样, 我们可以怎么用呢
我是设计者, 我允许使用者这么用 : XCls<string, list> mylst1;
. 这个用法是我传入一个容器, 并且传入容器的元素类型, 所以使用者就变得很有弹性了, 这里是希望里面做出一个链表, 链表里面的元素是 string
我可以指定任意的容器, 指定任意的元素类型, 进去以后被它组合起来
作为一个设计者, 当我想要我的使用者这么有弹性之后, 我这个第二模板参数这里, 必须是模板模板参数
因为你看使用者传进去的 list, 它是个模板, 它自己都还未定呢, 这个容器还需要指定元素类型, 就被放进去了 (放进注释那一部分)
不过, 很不幸 XCls<string, list> mylst1;
是错误的
那么错误在哪里呢 ? 不过这个已经和我们的主题模板模板参数无关了. 这一行就好像写出来一个
list<string>
. 一般我们不都是这么写的吗 ? 其实容器有第二和第三参数的, 我们一般不写是因为它们有默认值, 那你说对啊这里我的意思是放默认值啊, 不过可惜语法上过不了要解决这个问题, 要引入另外一个语法 :
template<typename T>
using Lst = list<T, allocator<T>>;
必须再加上这两行. 这两行就不解释了因为它是 C++ 2.0 新增加的语法
XCls<string, Lst> mylst2;
我们回到我们的主题, 模板模板参数
template<typename T,
template<typename T>
class SmartPtr
>
class XCls
{
private:
SmartPtr<T> sp;
public:
XCls () : sp(new T) { }
};
刚刚上面放的模板参数是 Container 容器, 刚刚很不幸的错误是因为容器需要好几个模板参数
现在这里换成了 SmartPtr, 而 SmartPtr ,至少有一两个智能指针只接收一个参数
这里就是使用传进来的一个智能指针, 并且以第一模板参数 T 作为智能指针里面的参数
刚刚的设计和现在是差不多一样的
现在我们来看看下面的使用
XCls<string, shared_ptr> p1;
XCls<double, unique_ptr> p2; // X
XCls<int, weak_ptr> p3; // X
XCls<long, auto_ptr> p4;
打叉的部分不是上面设计错了, 而是因为这两行里面用到的 unique_ptr 和 weak_ptr 独特的性质而出错
我们看第一行和第四行是可以传进去的
这不是 template template parameter
template<class T, class Sequence = deque<T>>
class stack
{
friend bool operator== <> (const stack&, const stack&);
friend bool operator< <>(const stack&, const stack&);
protected:
Sequence c; // 底层容器
//...
}
这是标准库里面的代码, stack, 接受两个模板参数, 其中第二个有一个默认值, 而代码里面以 Sequence 这个东西为模型创建了一个对象出来.
当这么写的时候, 是下面这么用
stack<int> s1; // 由于第二个模板参数有默认值所以可以不写
stack<int, list<int>> s2;
如果我要写出第二模板参数, 我必须这么写, 它现在已经不是模板了, 虽然它是用模板设计出来, 但是这么写已经不是模板了, 已经写死了, 所以这一个已经不再是模板了.
所以不能说这是模板模板参数
刚刚希望传进去一个 list 就好, 并没有绑定任何东西, 这样它才能是一个模板