因为即使它们都是重载解析的可行选择,第二个函数模板比第一个更专业。
根据 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 是函数模板特化,根据 14.5.6.2 中描述的偏序规则,F1 的函数模板比 F2 的模板更特化。
§ 14.5.6.2 然后说明如何确定一个函数模板比另一个函数模板更专业。特别是,根据 14.5.6.2/2:
部分排序通过依次转换每个模板(参见下一段)并使用函数类型执行模板参数推导来选择两个函数模板中的哪一个比另一个更专业。推演过程确定模板中的一个是否比另一个更专业。如果是这样,更专业的模板是部分排序过程选择的模板。
标准中的正式定义可能很难解读,但它们的复杂性通常意味着明确地使语言表现得像我们在大多数情况下自然期望的那样。
我们对您提供的重载的直观期望是,std::shared_ptr<T>
当参数是类型时,应该选择接受 a 的重载std::shared_ptr<int>
,因为它似乎std::shared_ptr<>
专门处理对象,因此它看起来是一个更好(更专业)的候选者。比不受约束的过载。
将这种直观的期望转化为一组明确的规则的正式程序可能听起来很复杂,但在我们的情况下遵循它并不是特别困难,我们想确定这种过载是否:
template<typename T>
void f(std::shared_ptr<T>);
比这更专业:
template<typename U>
void f(U);
尽管在这种情况下,我们很容易根据我们的直觉来判断哪个更专业,但编译器必须依赖于算法,并且该算法必须在所有情况下都有效。
在这种情况下,机制将如下所示:
- 取第一个重载,将其模板参数替换
T
为类型参数(任何类型参数),例如int
,并实例化相应的签名 - 函数参数将具有 type std::shared_ptr<int>
;
- 是否总是可以通过提供该类型的对象(在这种情况下)作为其输入来调用第二个
shared_ptr<int>
重载,并从中推断出类型U
?
- 嗯,答案是肯定的。
U
将被推断为std::shared_ptr<int>
;
- 现在反过来:采用第二个重载,将其模板参数替换
U
为任何类型参数,例如bool
,并实例化相应的签名 - 函数参数将具有 type bool
;
- 是否总是可以通过提供该类型的对象 ( ) 作为其参数来调用第一个重载并
bool
从中推断出类型T
?
- 当然,这里的答案是否定的。没有办法推断
T
出std::shared_ptr<T>
匹配bool
;
- 结论:第一个重载比第二个更专业。
Of course, things get slightly more complicated when there is more than one template parameter and more than one function parameter, but the mechanism is pretty much the same.