C++模板匹配过程
示例代码如下
template <typename T> struct DoWork; // (0) 这是原型
template <> struct DoWork<int> {}; // (1) 这是 int 类型的特化
template <> struct DoWork<float> {}; // (2) 这是 float 类型的特化
template <typename U> struct DoWork<U*> {}; // (3) 这是指针类型的偏特化
DoWork<int> i; // (4)
DoWork<float*> pf; // (5)
编译器解析过程
(1)struct DoWork<int>
(2)struct DoWork<float>
struct DoWork (0) ---> //特化
//原型
(3)template <typename U> struct DoWork<U*> {};//指针类型的偏特化
编译器会维护两个字典 , 称为TemplateDict 储存着模板原型
第二个是 TemplateSpecDict 储存着模板的特化形式
TemplateDict[DoWork<T>] =
{
DoWork<int>,
DoWork<float>,
DoWork<U*>
};
在实例化(4)时会发生
//伪代码
templatePro = TemplateDict.find(DoWork) //先找到函数原型
template TemplateSpecDict.match(int)//在特化/偏特化表寻找int
看以下示例
template <typename T1, typename T2> struct X ;//模板原型
template <typename T1> struct X<T1,int*> (1)
template <typename T1> struct X<int,T1> (2)//其实这样写是错误的
template <> struct X<int,int*>(3)
template <typename T> struct X<unique_ptr<T>,share_ptr<T> >;
....
do something
....
X test<int , int*>
X会匹配到第三个 也就是和<int , int*>完全一致的(偏)特化模板
很符合直觉认知,但是为啥?
首先 特化和偏特化是可以嵌套的
其次偏特化时的模板形参,和原型的模板形参没有任何关系。和原型不同,它的顺序完全不影响模式匹配的顺序
最短路径寻找参数
在编译试图匹配第二个模板参数时 , 会尝试找到最接近给定参数的模板作为一个模式匹配,偏特化的实参列表中展现出来的“样子”,就是它能被匹配的原因。比如,
struct X<T, T>
中,要求模板的两个参数必须是相同的类型。而struct X<T, T*>
,则代表第二个模板类型参数必须是第一个模板类型参数的指针,比如X<float***, float****>
就能匹配上。 —参考资料
这样理解 , 当编译器尝试匹配一个指针int*时 此时
TemplateDict[X<T>] =
{
X<T*>;
X<T>;
};
此时会匹配到T* 因为 int* 更加接近于T*
同时 其他的类模板也可以作为偏特化时的“模式”出现,例如示例8,它要求传入同一个类型的unique_ptr
和shared_ptr
N3337, 14.8.2.5/8
令
T
是模板类型实参或者类型列表(如 int, float, double 这样的,TT
是template-template实参(参见6.2节),i
是模板的非类型参数(整数、指针等),则以下形式的形参都会参与匹配:
T,cv-list T,T*, template-name <T>, T&, T&&
T [ integer-constant ]
type (T), T(), T(T)
T type ::*, type T::*, T T::*
T (type ::*)(), type (T::*)(), type (type ::*)(T), type (T::*)(T), T (type ::*)(T), T (T::*)(), T (T::*)(T)
type [i], template-name <i>, TT<T>, TT<i>, TT<>
刚刚在前面还写了这样一个
template <typename T1> struct X<int, T1*>;//(1)
template <typename T1> struct X<T1, int*>;//(2)
前面有提到
模板形参,和原型的模板形参没有任何关系。和原型不同,它的顺序完全不影响模式匹配的顺序
要这么写 编译器就会不知道应该匹配到哪一个特化模板 , 从而导致错误了