模板的模板参数
|
注意,这个代码是无法通过编译的。因为编译器在匹配模板参数的时候,是看全部参数的,不会去考虑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
没有参数范围可以选择。只能在内部指定类型。
同理,可以扩展到多个参数的情况。
|
与
|
这两个也应该是等价的。在使用的时候,都需要在
|
这样的声明方式。