为什么第一个函数调用(cm(car);
)绑定到第一个函数?
据我所知,第二次调用绑定到第二个函数,因为它是非模板的,尽管两者都是完美的匹配。
如果第一个函数被定义为具有固定数组长度的非模板,则为:
void cm(const char (&h)[8]) {cout << "const char (&)[8]" << endl;}
再次在第二个选择中被选中(第二个调用将是不明确的那种方式)。
代码:
template<size_t N> void cm(const char (&h)[N])
{std::cout << " const (&)[N] " << endl;}
void cm(const char * h)
{cout << " const char * " << endl;}
int main()
{
char car[] = "errqweq";
const char ccar[] = "errqweq";
cm(car);
cm(ccar);
}
输出:
const (&)[N]
const char *
答案 0 :(得分:4)
第一个电话选择功能模板专业化 - 因为它是更好的匹配 让我们标记两个重载:
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
是一个比转换序列更好的转换序列 标准转换序列S2
if
S1
是S2
的正确子序列(比较13.3.3.1.1定义的规范形式的转换序列,排除任何 左值变换;身份转换序列是 被认为是任何非身份转换的后续行为 序列)或,如果不是,- [...]
数组到指针的转换是Lvalue转换,所以在这里不予考虑 - 就像在第二个例子中一样。资格转换有一个自己的类别:资格调整。因此,转换为(1)的参数是转换为(2)的参数的子序列:第一个是身份转换,第二个是资格转换,根据上面的段落,身份转换是子序列任何非身份转换。所以选择(1)。
正如您已经提到的那样,在第二种情况下,转换同样很好;由于转换为(2)s参数不是转换为(1)参数的子序列,因此上述引用不起作用。因此,[over.match.best] / 1适用。
鉴于这些定义,可行函数
F1
被定义为a 如果适用于所有参数,则比另一个可行函数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)为a时 参数表达式,隐式转换序列是标识 转换,除非参数表达式的类型是a 派生类的参数类型,在这种情况下是隐式的 转换序列是派生到基础的转换(13.3.3.1)。
[dcl.init.ref] / 5(在8.5.3中):
除了最后一个之外的所有情况(即创建和初始化a 暂时从初始化表达式),引用据说 直接绑定到初始化表达式。
2 [conv.array]:
“
N T
数组”或“未知数组”的左值或右值T
“的边界可以转换为”指向T
的指针“的prvalue。 结果是指向数组的第一个元素的指针。
T
可以是cv限定的,指针的类型也是如此。此处T
仅为char
,因此指针的类型指针指向char
=&gt; char*
。
答案 1 :(得分:2)
因为字符串&#34; errqweq&#34;直接写在代码中是只读的,因为它在运行时是存储器的一部分&#34; protected&#34;因为它是作为常数管理的。
使用const char* ccar;
或const char ccar[];
指向它是正确的。你指的是持有原始&#34; errqweq&#34;使用const说明符:编译器确保不会修改字符串。
但请看:char car[] = "errqweq";
为了给你提供一个可修改的缓冲区(正如你在没有const修饰符的情况下请求的那样),编译器在栈中创建一个包含8个元素(7个字符+ \ 0)的数组,复制它(即:初始化它)字符串&#34; errqweq&#34;
所以第一个调用是使用char buffer[8]
个参数,这个参数可以安全地转换为const char buffer[8]
。显然,阵列的固定大小与模板最匹配,而不是更多&#34;弱&#34;绑定需要&#34;只是&#34;一个常量指针。