一:废话html
今天在stackoverflow上看到一个关于c++模板specialization的问题:linux
他的English好像不是很标准(说不定是India三哥,哈哈),但比我强多了。废话很少说,问题简述以下:app
//#1 template<class X> void foo(X a) { cout << "Template 1" << endl; } //#2 template<class X> void foo(X *a) { cout << "Template 2" << endl; }
template<> void foo<>(int *a) { cout << "Specialization 1" << endl; }
那么这哥们的问题以下:less
1 这个函数是属于template #1呢仍是属于template #2呢?jsp
2 若是这个特例化定义在template #2以前和以后,结论会有差异吗?函数
其实看过c++模板的内容,但没怎么用过复杂的模板,只是简单的写一些模板函数,方便适应不一样的参数。 因此对模板特例化没有特别深刻了解, 对偏序机制也就没有什么概念。正巧遇到这个哥们问了这样一个问题,我试着去回答,可是无能为力,正好有一位大神帮他回答了,因而我也顺便请教了这位大神,他说这个偏序化机制在模板中是一个比较复杂的概念,涉及内容比较多。了解了这个之后,我Google了一点资料,写下这篇当心得。ui
二: 偏序化(Partial Ordering)spa
应该是这么翻译吧!先看下什么叫partial ordering?引用参考资料1里面的介绍:nuxt
A function template specialization might be ambiguous because template argument deduction might associate the specialization with
more than one of the overloaded definitions. The compiler will then choose the definition that is the most specialized. This process of selecting a function template definition is called partial ordering
三: 介绍
在介绍以前,先看看什么叫最特例化?举个例子:
//#1 template<class T> void f(T); //#2 template<class T> void f(T*); //#3 template<class T> void f(const T*);
上述三个模板中,特例化的程度从大到小依次为:
#3 > #2 > #1
若是如今有这样一个调用:
int *p = NULL; f(p);
那么编译器确定会选择#2模板,而不是#1模板,由于#2模板比#1模板更特例化。为何不选#3模板?由于还有一个规则,优先选择类型显式匹配的模板,若是调用#3号模板,须要隐式转换。
而后,接下来的问题是:编译器怎么知道#2模板比#1模板更特例化?下面就是我要说的partial ordering。编译器经过以下的方法来判断:
1 先选择两个函数模板,T1和T2
2 用假设的惟一类型X取代模板T1的参数
3 用被X取代后的T1的参数列表,带入T2,看T2是不是一个有效的模板。忽略全部的隐式转换。
4 反过来,先用X取代T2的参数,再把T2的参数列表带入T1,看看T1是否有效。
5 若是一个模板的参数好比T1对于另一个模板T2是有效的,可是反之不成立,那么就说这个模板T1不比T2更特例化。若是这两个模板的参数均可以相互代替,就说它们具备相同的特例性,这样会引发编译器混淆。
template<class T> void g(T) { } template<class T> void g(T&) { }
template<class T> void h(T) { } template<class T> void h(T, ...) { } //error C2668: 'h' : ambiguous call to overloaded function
可变参数不会引发编译器执行partial ordering规则,因此这两种模板也会引发歧义。
四:使用
partial ordering的判断实例:
1 对于一个模板,特定类型的参数比通常类型的参数,更具备特例性
2 带有T*的模板比T的模板具备特例性。由于一个假设的类型X*也能够被认为是T类型的, 相反一个有效的T类型参数,可能不是X*类型的。
3 const T比T更特例化,道理同上。
4 const T*比const T更特例化,理由也是同样的。
template <class T> void f(T) { cout<<"f(T):Less specialized function called"<<endl; } template <class T> void f(T*) { cout<<"f(T*):More specialized function called"<<endl; } template <class T> void f(const T*) { cout<<"f(const T*):Even more specialized function for const T*"<<endl; } int _tmain(int argc, _TCHAR* argv[]) { int i =0; const int j = 0; int *pi = &i; const int *cpi = &j; f(i); // Calls less specialized function. f(pi); // Calls more specialized function. f(cpi); // Calls even more specialized function. // Without partial ordering, these calls would be ambiguous. }
什么状况下,编译器会执行这样的一个Partial Ordering?文献1给出了几种状况:
· Calling a function template specialization that requires overload resolution.
· Taking the address of a function template specialization.
· When a friend function declaration, an explicit instantiation, or explicit specialization refers to a function template specialization.
· Determining the appropriate deallocation function that is also a function template for a given placement operator new.
(2) 获取函数模板特例的地址
(3) 当一个友元函数声明,或者显示实例化,或者引用函数模板的显示特例化
(4) 对一个new出来的内存进行销毁时(这个new函数也是模板函数),如何选择相应的释放函数也会引起partial ordering。
REFERENCE: