今天在
stackoverflow上看到一个关于c++模板specialization的问题:
他的English好像不是很标准(说不定是India三哥,哈哈),但比我强多了。废话不多说,问题简述如下:
点击(此处)折叠或打开
-
//#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;
-
}
那么这哥们的问题如下:
1 这个函数是属于template #1呢还是属于template #2呢?
2 如果这个特例化定义在template #2之前和之后,结论会有差别吗?
其实看过c++模
板的内容,但没怎么用过复杂的模板,只是简单的写一些模板函数,方便适应不同的参数。 所以对模板特例化没有特别深入了解, 对偏序机制也就没有什么概
念。正巧遇到这个哥们问了这样一个问题,我试着去回答,但是无能为力,正好有一位大神帮他回答了,于是我也顺便请教了这位大神,他说这个偏序化机制在模板
中是一个比较复杂的概念,涉及内容比较多。了解了这个以后,我Google了一点资料,写下这篇小心得。
二: 偏序化(Partial Ordering)
应该是这么翻译吧!先看下什么叫
partial ordering?引用参考资料1里面的介绍
-
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。编译器通过如下的方法来判断:
-
先选择两个函数模板,T1和T2
-
用假设的唯一类型X取代模板T1的参数
-
用被X取代后的T1的参数列表,带入T2,看T2是否是一个有效的模板。忽略所有的隐式转换。
-
反过来,先用X取代T2的参数,再把T2的参数列表带入T1,看看T1是否有效。
-
如果一个模板的参数比如T1对于另外一个模板T2是有效的,但是反之不成立,那么就说这个模板T1不比T2更特例化。如果这两个模板的参数都可以相互代替,就说它们具有相同的特例性,这样会引起编译器混淆。
举两个会引起混淆的一个例子,比如:
(1)
template<class T> void g(T) { }
template<class T> void g(T&) { }
这两个模板的参数可以相互替代,所以编译器会报错
(2)
template<class T> void h(T) { }
template<class T> void h(T, ...) { } //error C2668: 'h' : ambiguous call to overloaded function
可变参数不会引起编译器执行partial ordering规则,所以这两种模板也会引起歧义。
四:使用
partial ordering的判断实例:
对于一个模板,特定类型的参数比一般类型的参数,更具有特例性
带有T*的模板比T的模板具有特例性。因为一个假设的类型X*也可以被认为是T类型的, 相反一个有效的T类型参数,可能不是X*类型的。
const T比T更特例化,道理同上。
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.
(1) 调用函数模板特例时,涉及到重载决议
(2) 获取函数模板特例的地址
(3) 当一个友元函数声明,或者显示实例化,或者引用函数模板的显示特例化
(4) 对一个new出来的内存进行销毁时(这个new函数也是模板函数),如何选择相应的释放函数也会引发partial ordering。
REFERENCE:
1
2
3
4
转自:
http://www.cnblogs.com/wb-DarkHorse/p/3264171.html
阅读(876) | 评论(0) | 转发(0) |