直接列表初始化编译成功,但正常的直接初始化失败,为什么?

时间:2015-09-09 02:22:00

标签: c++ initialization overload-resolution

例如,代码如下:

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&&)

1 个答案:

答案 0 :(得分:8)

从最新的官方标准C ++ 14开始,你的第一次初始化并不含糊。 [over.match.list]:

enter image description here

由于不存在初始化列表构造函数,因此我们进入“第二阶段”。现在考虑[over.best.ics] / 4:

enter image description here

我们的元素是{0}。因此这不允许(用户定义的)转换{0} - &gt; A用于复制构造函数。显然,如果我们不在[over.match.list]的第二阶段,这不适用,因此对于B c({0})的示例,c和两个构造函数都不会发生列表初始化被认为是。

CWG issue 1467

第一次初始化与第二次初始化一样模糊。编译器还没有实现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}本身就是一个初始化程序列表,该项目符号将使您的第一次初始化再次成形。