例如,代码如下:
struct A { A(int); };
struct B { B(A); };
int main()
{
B b{{0}}; // OK
B c({0}); // error
}
错误消息是:
f.cc: In function 'int main()':
f.cc:7:9: error: call of overloaded 'B(<brace-enclosed initializer list>)' is ambiguous
B c({0}); // error
^
f.cc:7:9: note: candidates are:
f.cc:2:12: note: B::B(A)
struct B { B(A); };
^
f.cc:2:8: note: constexpr B::B(const B&)
struct B { B(A); };
^
f.cc:2:8: note: constexpr B::B(B&&)
答案 0 :(得分:8)
从最新的官方标准C ++ 14开始,你的第一次初始化并不含糊。 [over.match.list]:
由于不存在初始化列表构造函数,因此我们进入“第二阶段”。现在考虑[over.best.ics] / 4:
我们的元素是{0}
。因此这不允许(用户定义的)转换{0}
- &gt; A
用于复制构造函数。显然,如果我们不在[over.match.list]的第二阶段,这不适用,因此对于B c({0})
的示例,c
和两个构造函数都不会发生列表初始化被认为是。
第一次初始化与第二次初始化一样模糊。编译器还没有实现CWG #1467 - 它的解析删除了上面引用的项目符号(4.5) 请参阅#2076,其中选择还原更改:
issue 1467的决议提出了一些看似合理的结构 病态的。例如,
struct A { A(int); }; struct B { B(A); }; B b{{0}};
现在这是模棱两可的,因为文字不允许用户定义
B
的复制和移动构造函数的转换已从中删除 13.3.3.1 [over.best.ics]第4段。
“文本”是上述要点。理查德史密斯提出以下措辞:
对于非类类型,我们允许从单项列表进行初始化 仅当列表中的元素本身不是a时才执行复制 list(13.3.3.1.5 [over.ics.list] bullet 9.1)。 类似的规则 这种情况将在13.3.3.1 [over.best.ics]中加回子弹 第4段,但仅限于初始化程序本身是一个 初始化列表:
第二阶段 13.3.1.7 [over.match.list]当初始化列表只有一个元素时 它本身就是一个初始化列表,其中target是第一个参数 构造函数
类X
,转换是 到X
或引用(可能是cv-qualified)X
,
由于初始化程序{0}
本身就是一个初始化程序列表,该项目符号将使您的第一次初始化再次成形。