use*_*080 31 c++ language-lawyer uniform-initialization c++11 list-initialization
请考虑以下代码段:
#include <iostream>
struct A {
A() {}
A(const A&) {}
};
struct B {
B(const A&) {}
};
void f(const A&) { std::cout << "A" << std::endl; }
void f(const B&) { std::cout << "B" << std::endl; }
int main() {
A a;
f( {a} ); // A
f( {{a}} ); // ambiguous
f( {{{a}}} ); // B
f({{{{a}}}}); // no matching function
}
Run Code Online (Sandbox Code Playgroud)
为什么每个调用都会编写相应的输出?支撑数如何影响均匀初始化?支撑精益如何影响这一切?
Dav*_*ing 17
过载分辨率很有趣.
{a}
具有完全匹配等级,用于初始化(临时)const A&
参数,该参数超出用户定义的转换B(const A&)
作为实现{a}
.此规则已在C++ 14中添加,以解决列表初始化中的歧义(以及对聚合的调整).
请注意,永远不会创建名义临时:在重载决策选择之后f(const A&)
,引用只是初始化以引用a
,并且即使对于非可复制类型,此解释也适用.
const A&
参数(如上所述)初始化为构造函数的任何一个 A
或B
,因此调用是不明确的.A(const A&)
禁止重复调用复制构造函数(此处)作为多个用户定义的转换 -而不是在每个重载分辨率级别允许一次此类转换.因此,最外面的大括号必须在第二种情况下B
从A
初始化的{{a}}
as(允许)初始化a .(大括号的中间层可以初始化a B
,但是禁止使用外层复制它,并且没有其他任何东西可以尝试初始化.)不涉及支撑锥度 - 我们不知道允许它的最外层目标类型.