模板的模板参数

本文介绍了C++中的模板模板参数,重点讲述了如何在STL的stack类模板中使用这一特性。通过示例展示了如何仅指定容器类型而不指定元素类型,讨论了与STL容器的默认模板参数匹配的问题,以及在不同STL版本中的不兼容性。同时提到了模板模板参数的匹配要求和在函数模板中的不可用性。

1、概念

         模板的模板参数(template template parameters),这个名字有点长,首先要理解什么是模板的模板参数。需要知道的是函数模板是不支持模板的模板参数的,所以这儿所指的模板的模板参数就是类模板的模板参数,即对一个类模板,它的模板参数本身也是一个模板,更确切地说是一个类模板。

2、例子

         为了说明怎样使用模板的模板参数,以STL中的容器适配器stack为例较为恰当。下面是SGI-STL stack的部分源码:

template<typename T, typename Sequence = deque<T> >
class stack
{
protected:
         Sequence c;
//…
};

         从源码可以看出来,stack的默认容器是deque,一般可以满足用户的需求,用户也可以另外指定容器。如指定vector作为stack的底层容器, 定义如下:

         stack<int,std::vector<int> > s;        //别忘了”#include<stack>”和 “#include <vector>”

stack类模板的第二个模板参数是一个类型,在这儿我们指定为vector<int>,从stack的定义我们可以知道,程序员如果要替换缺省的内部容器的话,必须两次指定元素的类型,如上面两次指定了int。然而,如果我们使用模板的模板参数,就可以只指定容器的类型而不需要指定所含元素的类型,于是我们可以这样创建一个stack对象,如下:

stack<int, std::vector> s;

为了获得这个特性,我们需要把stack类模板的第二个模板参数指定为模板的模板参数(呵呵,我们在修改SGI-STL源码),如下:

template<typename T,
		template <typename E> class Sequence = std::deque >
class stack
{
protected:
         Sequence<T> c;
//…
};

我们把第2个模板参数声明为了一个类模板:

         template<typename E> class Sequence  = std::deque

缺省值也从std::deque<T>变成了std::deuqe,第二个参数必须是一个类模板,并由第一个模板参数传递进来的类型进行实例化。于是我们可以如下创建一个stack对象:

         stack<int, std::vector> s;

如果我们在编译器上编译,会得到错误信息:缺省值std::deque和模板的模板参数Sequence不匹配。其实如是你熟悉STL,应该知道问题出在哪儿。对于STL的容器vector,deque, list, map, set, multimap, multiset,它们都有一个缺省的模板参数,它便是空间配置器allocator,它负责容器对空间的配置与管理。配置器实现了动态空间配置,空间管理,空间释放,它本质上是一个类模板(class template)。SGI-STL的空间配置器实现相对比较复杂,内容比较多,也不是本篇的主题,有兴趣的网友可以参考侯捷的STL源码剖析。下面给出SGI-STL allocator和deque的类模板声明,如下:

template<typename _Tp>  
class  allocator;    
template<typename _Tp, typename _Alloc = std::allocator<_Tp> > 
class  deque;

         从上面的声明可以看出deuqe和allocator只是一个类模板,而allocator是类模板deque的第二个模板参数,是缺省的空间配置器(用户也可以定义自己的空间配置器)。现在我们再来分析错误原因。

         对于stack类模板声明:

template<typename T, 

template <typename E> class Sequence = std::deque>

class stack;

它的第二个模板参数template <typename E> class Sequence = std::deque也是一个类模板,它只有一个模板参数 ,即template<typename E>中的E,但对std::deque却有两个模板参数(见上面的声明),故错误信息会提示缺省值std::deque和模板的模板参数Sequence不匹配。于是我们可以如下重新声明stack类,如下:

template<typename T,
           	template<typename  E, typename  Alloc = allocator<T> >
			class Sequence = std::deque>
class stack
{
         protected:
         Sequence<T> c;
         //…
}

         由于我们在stack类的实现中并没有用到模板参数E和Alloc, 所以我们可以将其省略。如下:

template<typenameT,
           template<typename  , typename  = allocator<T> >
class Sequence = std::deque> class stack;

3、注意事项:

(1)由于STL版本比较多,故实现也存在差异,如空间配置器就有所不同,所以上面代码不具有可移植性。

(2)模板的模板实参要求与模板的模板参数精确匹配。

(3)函数模板不具有模板的模板参数

4、更多参考资料

[1]侯捷著.STL源码剖析[M],湖北华中科技大学出版社.2011.12

[2][美]David Vandevoorde,Nicolai M.Josuttis著.陈伟柱译.C++ Templates.北京.人民邮电出版社

[3][美]Nicolai M.Josuttis著.侯捷,孟岩译.C++标准程序库.湖北.华中科技大学出版社

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值