重载解决方案分多个步骤完成。
首先,通过名称查找,我们选择可行的候选人列表。在这种情况下,即:
template <class U, class T>
void foo(U&, T&); // with U = int, T = double
template <class T>
void foo(int&, const T&) // with T = double
接下来,我们确定每个可行候选者的每个参数所需的转换顺序。这是[over.ics.rank]:
标准转换序列S1是比标准转换序列更好的转换序列
S2 如果 [...]
- S1 是 S2 的适当子序列(比较规范形式的转换序列
由 13.3.3.1.1 定义,不包括任何左值变换;身份转换序列是
被认为是任何非身份转换序列的子序列),或者,如果不是,
- S1的rank优于S2的rank,或者S1和S2的rank相同且可区分
根据以下段落中的规则,或者,如果不是这样,
对于第一次调用,转换顺序为(Identity, Identity)。对于第二次调用,转换顺序为(Identity,Identity)。所以我们在那里是平等的。这些要点都没有区分这两个电话。所以我们继续前进。
- S1 和 S2 是引用绑定 (8.5.3),两者均不引用 a 的隐式对象参数
没有引用限定符声明的非静态成员函数,并且 S1 将右值引用绑定到
一个右值,S2 绑定一个左值引用。
无关紧要。
- S1 和 S2 是引用绑定 (8.5.3),S1 将左值引用绑定到函数左值和
S2 将右值引用绑定到函数左值。
没有。
- S1 和 S2 的区别仅在于它们的资格转换并产生相似的类型 T1 和 T2 (4.4),
分别,类型 T1 的 cv 限定签名是 cv 限定的真子集
T2 类型的签名。
资格转换是指针的事情,不是。
- S1和S2是引用绑定(8.5.3),引用所引用的类型相同
顶级 cv 限定符除外的类型,以及由 S2 初始化的引用所引用的类型
比由 S1 初始化的引用所引用的类型更具有 cv 限定。
在这种情况下,第一个重载将其第二个参数作为double&,而第二个重载采用const double&。前者的 cv 资格不如后者,所以我们在此停止 - 更喜欢 foo(U&,T&)。
只有在确定哪种转换顺序更好的步骤之后,我们才能进入首选更专业模板的步骤。 [over.match.best] 中的完整规则排序为:
鉴于这些定义,一个可行函数 F1 被定义为比另一个可行函数更好的函数
F2 如果对于所有参数 i,ICSi(F1) 不是比 ICSi(F2) 更差的转换序列,则
- 对于某些参数 j,ICSj(F1) 是比 ICSj(F2) 更好的转换序列,或者,如果不是这样,
这就是我们刚刚经历的。
- 上下文是由用户定义的转换初始化 [ ... ]i>
- 上下文是直接引用绑定的转换函数初始化 [...]
- F1 不是函数模板特化,F2 是函数模板特化,或者,如果不是,
- F1和F2是函数模板特化,F1的函数模板更加特化
根据 14.5.6.2 中描述的部分排序规则,而不是 F2 的模板。
这就是我们选择foo(U&, T&) 的原因。但是,如果您删除 const,那么两个转换序列在所有步骤中都是相同的 - 因此,在这一点上,更专业的模板 (foo(int&, T&)) 会胜出。
请注意,更专业的是确定最佳候选者的最后机制。这是决胜局的最后一场。
另请注意,模板扣除的数量是无关紧要的。 可能在作为模板的重载和不是模板的重载之间进行选择 - 但在具有 x 模板参数的重载和具有 y > x 模板参数的重载。