为什么这些重载不会产生歧义?

7
以下代码可以在gcc和clang下编译通过。
template <typename T>
struct identity
{
    typedef T type;
};

template <typename T>
void foo(typename identity<T>::type);

template <typename T>
void foo(T);

int main()
{
    foo<int>(0);
}

看起来过载分辨率正在选择第一个重载(identity<T>::type)。

有人能解释一下为什么这些重载不是模棱两可的吗?据我所知,它们之间唯一的区别就是第一个参数是非推导上下文,而第二个参数则不是,但既然我明确提供了模板参数,我不明白为什么这会有影响。


有趣。显然,如果您通过不明确实例化foo<int>(0)而是使用foo(0)启用类型推断,则会选择第二个函数(身份元函数没有类型推断)。@Andy Prowl:我不想质疑您的答案,但要指出您的推理并不像看起来那么明显。给foo参数一个默认值,并调用foo<int>()而不带参数。您的论证仍然适用,但现在重载确实是模棱两可的,就像HighCommander4所预期的那样。函数模板的显式模板实例化很复杂。 - Patrick Fromberg
1个回答

7
两个重载都是可行的,但前者比后者更专业化,因此它被重载决议所选择。
根据C++11标准中的第13.3.3/1段关于重载决议的规定:
[...]如果对于所有参数i,ICSi(F1)不是比ICSi(F2)更差的转换序列,则定义可行函数F1优于另一个可行函数F2,然后
- 对于某些参数j,ICSj(F1)是比ICSj(F2)更好的转换序列,或者如果不是这样的话, - 上下文是通过用户定义的转换进行初始化(请参见8.5、13.3.1.5和13.3.1.6),并且从F1的返回类型到目标类型(即正在初始化的实体的类型)的标准转换序列是比从F2的返回类型到目标类型的标准转换序列更好的转换序列。[...]或者如果不是这样的话, - F1是非模板函数,而F2是函数模板特化,或者如果不是这样的话, - F1和F2都是函数模板特化,而F1的函数模板比F2的函数模板更专业化,符合14.5.6.2中描述的部分排序规则。
确定两个函数模板中哪一个比另一个更专业化的过程在第14.5.6.2/2段中概述:
部分排序通过依次转换每个模板(见下一段)并使用函数类型执行模板参数推导来选择两个函数模板中的哪一个比另一个更专业化。推导过程确定了其中一个模板是否比另一个模板更专业化。如果是这样,那么更专业化的模板是由部分排序过程选择的。

有道理,谢谢!(我直觉地认为“比...更专业”意味着“适用于更小的输入类型集”,这是我认为的意图,但我明白这个术语的技术定义并不完全是那样。) - HighCommander4

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接