12_template template parameter 模板模板参数

template template parameter 模板模板参数

模板模板参数

我现在设计了一个 template, 里面的第二个模板参数, 这个模板参数本身又是一个 template

这个语法应该怎么写呢, 就是下面注释的这一块

template<typename T,
        template<typename T>    // 第二个模板参数, 本身又是一个模板
            class Container>
        >
class XCls
{
    private:
        Container<T> c;
    public:
        //...
};

只有在模板尖括号里面, typenameclass 共通, 其它地方都不可以

这个 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 就好, 并没有绑定任何东西, 这样它才能是一个模板