模板的模板参数
|
注意,这个代码是无法通过编译的。因为编译器在匹配模板参数的时候,是看全部参数的,不会去考虑A的偏特化版本。
The compiler considers the partial specializations based on a template template argument once you have instantiated a specialization based on the corresponding template template parameter. The following example demonstrates this:
|
如果仔细地看一下B这个类,就会发现,T/U好像没有什么用。因为在B的内部声明的里面从来没有用到这两个类型,如果要用这两个类型应该怎么办?
|
这样是会报错的,因为template<class T, class U> class V只会用来修饰类V而不会用来修饰B。所以在编译的时候,会在B里面说,T/U没有定义。
那么,如果想让B类里面有如下声明:
|
应该怎么办?
应该把B类的声明改成如下:
|
这里要特别注意看声明。在声明V的时候,所有的这个V会引用到的变量都是在template<typename T, typename U, typename X, ..> B也就是T, U, X这三个里面取。至于具体取哪个,并不能从template的声明里面看出来。
真正要实例化V类的时候,也就是B的内部声明的时候,才会知道V到底是怎么实例化的。
|
所以可以总结一下,关于模析模板参数。
- 如果模板模板参数想起作用,那么只能在
<typename X, typename Y, typename Z, template<class, class> class V>里面取,并且声明模板板参数的时候,不能写明template<class T, class U> class V,而是需要写成template<class, class> class V这种形式,表示参数都从前面的列表里面选择。 - 如果是写成
template<class T, class U> class V这种格式,并且T/U不在外部列表里面。比如template<typename T, typename U, typename X, template<typename T, typename U> class V>这里会因为T/U重复声明,导到编译不过。那么需要改写成template<typename T, typename U, typename X, template<typename A, typename B> class V> class B {};。但是按照这种写法,模板参数A/B就只能在B类定义的时候内部各种实例化,而不能在外部指定。
所以,也可以总结成。
- 如果想定义
B类的时候,直接也把内部类A的定义决定了。那么,声明的时候,必须采用1. - 如果想
B类内部自由定义A类的实例化,那么必须采用格式2.
模板模板参数的取值范围
模板模板参数的取值范围可以是:
- 类型声明在前面,比如
<typename X, typename Y, typename Z, template<class, class> class V>。这个时候,类V的模板参数可取范围是X, Y, Z。 - 类型声明在后面,比如
<template<class, class> class V, typename X, typename Y, typename Z>也是同样可以取到X/Y/Z的。
|
再如
|
缺省值
|
只是需要注意的是,这里的Deque的声明也需要是template <typename> class Deque { };这样。也就是只有一个模板参数。
注意这里的Deque不是STL里面Deque。
无用的模板参数
有时候,如果采用如下声明,会导致相同的结果。
|
在这里,Wrap的声明得到的效果就与
|
得到同样的效果。因为template<template<typename T> typename V>会导致V没有参数范围可以选择。只能在内部指定类型。
同理,可以扩展到多个参数的情况。
|
与
|
这两个也应该是等价的。在使用的时候,都需要在
|
这样的声明方式。