jac*_*k X 6 c++ language-lawyer c++11
这里有一些代码
#include <iostream>
struct A {
A(int) {}
};
struct B {
B(A) {
std::cout<<"0"<<std::endl;
}
B(B const&) {
std::cout << "1" << std::endl;
}
B(B&&) {
std::cout << "2" << std::endl;
}
};
int main() {
B b0{{0}}; // this is ok #1
B b( {0} ); //this is error #2
}
Run Code Online (Sandbox Code Playgroud)
g ++报告:
main.cpp: In function ‘int main()’:
main.cpp:17:11: error: call of overloaded ‘B(<brace-enclosed initializer list>)’ is ambiguous
B b({ 0 });
^
main.cpp:12:2: note: candidate: B::B(B&&)
B(B&&) {
^
main.cpp:9:2: note: candidate: B::B(const B&)
B(B const&) {
^
main.cpp:6:2: note: candidate: B::B(A)
B(A) {
Run Code Online (Sandbox Code Playgroud)
lang报告:
main.cpp:17:4: error: call to constructor of 'B' is ambiguous
B b({ 0 });
^ ~~~~~
main.cpp:6:2: note: candidate constructor
B(A) {
^
main.cpp:12:2: note: candidate constructor
B(B&&) {
^
main.cpp:9:2: note: candidate constructor
B(B const&) {
^
1 error generated.
Run Code Online (Sandbox Code Playgroud)
{0}将转换为临时对象A,并且将选择构造函数B(A),#1和#2均为“直接构造函数”形式,为什么#1可以,#2具有三个候选构造函数且模棱两可?
因为对于 #1, [over.best.ics]/4不允许复制和移动构造函数(强调我的):
\n\n\n\n\n然而,如果目标是
\n\n\n
\n\n- 构造函数的第一个参数或
\n- 用户定义的转换函数的隐式对象参数
\n并且构造函数或用户定义的转换函数是候选\n
\n\n\n
\n\n- \n
[over.match.ctor],当参数是类复制初始化第二步中的临时参数时,
- \n
[over.match.copy]、[over.match.conv] 或 [over.match.ref](在所有情况下),或
- \n
[over.match.list] 的第二阶段,此时初始值设定项列表恰好有一个元素本身就是初始值设定项列表,并且目标\n 是类 X 的构造函数的第一个参数,并且转换\n 为 X或参考简历 X,
不考虑用户定义的转换序列。[\xe2\x80\x89注意: 这些\n规则可防止在重载解析期间应用多个用户定义的转换\n,从而避免无限递归。\n \xe2\x80\x89\xe2\x80\x94\xe2 \x80\x89结束注\xe2\x80\x89]
\n
({...})
所以区分和的是语言规则{{...}}
。请注意({...})
情况属于 [over.match.ctor],但参数不是类复制初始化第二步中的临时参数,因此第一个项目符号不适用。
您可以进一步阅读Issue 2076来了解它的目的是禁止在{{...}}
:
\n\n问题 1467 的解决使一些看似合理的结构变得不合理。例如,
\n\nRun Code Online (Sandbox Code Playgroud)\n\nstruct A { A(int); };\nstruct B { B(A); };\nB b{{0}};\n
现在这是不明确的,因为禁止 B 的复制和移动构造函数的用户定义转换的文本已从 16.3.3.1 [over.best.ics] 第 4 段中删除...
\n