第一次调用选择函数模板特化 - 因为它是更好的匹配。
让我们标记两个重载:
template<size_t N> void cm(const char (&h)[N]) // (1) - the specialization
{std::cout << " const (&)[N] " << endl;}
void cm(const char * h) // (2)
{cout << " const char * " << endl;}
对于 (1),car 绑定到一个引用。这是一个身份转换1。
对于 (2),在 car 的数组到指针转换后,产生 char*2,必须进行限定转换,因此 char* 变为
char const* .现在调用这个:
标准转换序列S1 比转换序列更好
标准转换序列S2if
-
S1 是 S2 的正确子序列(比较 13.3.3.1.1 定义的规范形式的转换序列,不包括任何
左值变换;身份转换序列是
被认为是任何非身份转换的子序列
序列)或者,如果不是这样,
- […]
数组到指针的转换是左值转换,所以这里不考虑它——就像在第二个例子中一样。不过,资格转换有一个自己的类别:资格调整。因此,转换为 (1) 的参数是转换为 (2) 的参数的子序列:第一个是恒等转换,第二个是资格转换,根据上面的段落,恒等转换是任何非身份转换。所以选择了(1)。
正如您自己已经提到的,在第二种情况下,转化率同样好;上面的引用不起作用,因为转换为 (2)s 参数不是转换为 (1) 的参数的子序列。因此,[over.match.best]/1 适用。
鉴于这些定义,一个可行的函数F1 被定义为
如果所有参数都比另一个可行的函数F2 更好的函数
i,ICSi(F1)不是比ICSi(F2)差的转换序列,那么
- 对于某些参数 j,ICSj(F1) 是比 ICSj(F2) 更好的转换序列,或者,如果不是这样,
- 上下文是由用户定义的转换 […] 进行的初始化,或者,如果不是这样,
-
F1 是非模板函数,F2 是函数模板特化,
所以(2)选择了一个。如果函数模板不是模板而是带有参数
char const (&)[8] 的函数,则调用将是模棱两可的 as Clang correctly says。
1 [over.ics.ref]/1:
当引用类型的参数直接绑定 (8.5.3) 到
参数表达式,隐式转换序列是恒等式
转换,除非参数表达式的类型是
参数类型的派生类,在这种情况下隐式
转换序列是派生到基础的转换 (13.3.3.1)。
[dcl.init.ref]/5(在 8.5.3 中):
在所有情况下,除了最后一个(即,创建和初始化一个
来自初始化表达式的临时),该引用被称为
直接绑定到初始化表达式。
2 [conv.array]:
“N T 数组”或“未知数组”类型的左值或右值
T 的边界可以转换为“指向T 的指针”类型的纯右值。
结果是指向数组第一个元素的指针。
T 可以是 cv 限定的,指针的类型也是如此。这里T 就是char,所以指针的类型是指向char => char*。