gd1*_*gd1 30 c++ templates language-lawyer overload-resolution
#include <iostream>
template<typename T>
struct identity
{
typedef T type;
};
template<typename T> void bar(T) { std::cout << "a" << std::endl; }
template<typename T> void bar(typename identity<T>::type) { std::cout << "b" << std::endl; }
int main ()
{
bar(5); // prints "a" because of template deduction rules
bar<int>(5); // prints "b" because of ...?
return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)
我预计bar<int>(5)至少会产生歧义.这里涉及到关于模板函数重载决策的疯狂规则?
Bar*_*rry 17
一旦我们得到候选函数集(两个bars),然后将其缩小到可行函数(仍然是bars),我们必须确定最佳可行函数.如果有多个,我们会出现歧义错误.我们采取的确定最佳步骤的步骤在[over.match.best]中列出:
[A]可行函数F1被定义为比另一个可行函数F2更好的函数,如果对于所有自变量i,ICS i(F1)不是比ICS i(F2)更差的转换序列,然后
- 对于某些自变量j, ICS j(F1)是比ICS j(F2)更好的转换序列,如果不是,
两个函数都采用类型的参数int,因此两个转换序列都是相同的.我们继续.
- 上下文是用户定义的转换初始化[...]
不适用.
- 上下文是转换函数的初始化,用于对函数类型的引用的直接引用绑定(13.3.1.6),[...]
不适用.
- F1不是函数模板特化,F2是函数模板特化,或者,如果不是,
两者bar<int>都是函数模板特化.因此,我们进入最后一个要点,以确定最佳可行功能.
- F1和F2是功能模板特化,根据14.5.6.2中描述的偏序规则,F1的功能模板比F2的模板更专业.
部分排序规则基本上归结为我们为两个bar重载的参数合成新的唯一类型,并在另一个重载上执行模板推导.
首先考虑"b"过载.合成类型typename identity<Unique1>::type并尝试执行模板推导T.这成功了.最简单的模板演绎有.
接下来,考虑"a"过载.合成类型Unique2并尝试执行模板推导typename identity<T>::type.这失败了!这是一个非推断的上下文 - 没有扣除可以成功.
由于模板类型推导仅在单个方向上成功,因此bar(typename identity<T>::type)过载被认为更加专业化,并被选为最佳可行候选者.
bogdan提出了另一个有趣的案例来看待部分排序.请考虑比较:
template <typename T> void bar(T, T); // "c"
template <typename T> void bar(T, typename identity<T>::type ); // "d"
bar(5,5);
bar<int>(5, 5);
Run Code Online (Sandbox Code Playgroud)
同样,两个候选者都是可行的(这次甚至没有明确指定T),所以我们看看部分排序规则.
对于"c"重载,我们合成类型的参数UniqueC, UniqueC并尝试执行演绎T, typename identity<T>::type.这成功(带T == UniqueC).所以"c"至少与"d"一样专业.
对于"d"重载,我们合成类型的参数UniqueD, typename identity<UniqueD>::type并尝试执行演绎T, T.这失败了!参数是不同类型的!所以"d"至少不如"c"那么专业.
因此,调用"c"重载.