列表初始化的重载解决规则是什么

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具有三个候选构造函数且模棱两可?

xsk*_*xzr 3

因为对于 #1, [over.best.ics]/4不允许复制和移动构造函数(强调我的):

\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,

  • \n
\n\n

不考虑用户定义的转换序列。[\xe2\x80\x89注意: 这些\n规则可防止在重载解析期间应用多个用户定义的转换\n,从而避免无限递归。\n \xe2\x80\x89\xe2\x80\x94\xe2 \x80\x89结束注\xe2\x80\x89]

\n
\n\n

({...})所以区分和的是语言规则{{...}}。请注意({...})情况属于 [over.match.ctor],但参数不是类复制初始化第二步中的临时参数,因此第一个项目符号不适用。

\n\n

您可以进一步阅读Issue 2076来了解它的目的是禁止在{{...}}

\n\n
\n

问题 1467 的解决使一些看似合理的结构变得不合理。例如,

\n\n
struct A { A(int); };\nstruct B { B(A); };\nB b{{0}};\n
Run Code Online (Sandbox Code Playgroud)\n\n

现在这是不明确的,因为禁止 B 的复制和移动构造函数的用户定义转换的文本已从 16.3.3.1 [over.best.ics] 第 4 段中删除...

\n
\n