为什么这种直接初始化有效? (C ++ 17)

时间:2018-10-26 03:07:23

标签: c++ initialization language-lawyer c++17

请考虑以下两个类:

class B
{
public:
   B() { }
   B(const B& b) = delete; //Move ctor not implicitly declared
};


class A
{
public:
   A() { }

   operator B()
   {
       return B();
   }
};

我可以看到为什么此代码可以正常编译:

A a;
B b = a;

遵循copy-initialization的规则,对象“ a”被转换为类型B的prvalue,并且由于在C ++ 17中不再需要复制构造函数,因此没有错误:

  

如果T是一个类类型,并且该类型的cv不合格版本   other不是T或不是从T派生的,或者T不是非类类型,而是   其他类型是一个类类型,用户定义的转换序列   可以将other的类型转换为T(或转换为T的类型   如果T是一个类类型并且有转换函数可用)是   检查并通过过载解析选择最佳的。的   转换的结果,是prvalue临时值(直到   C ++ 17)prvalue表达式(自C ++ 17起),如果转换构造函数是   使用,然后用于直接初始化对象。最后一步是   通常进行优化,然后构造转换结果   直接在分配给目标对象的内存中   需要适当的构造函数(移动或复制)才能访问   即使不使用它。 (直到C ++ 17)

但是为什么直接列表初始化也要编译?

A a;
B b{ a };

list-initialization中找不到任何措辞说明在这种情况下编译器应尝试将A转换为B。仅考虑构造函数的重载解析:

  

如果上一阶段未产生匹配项,则T的所有构造函数   参与针对一组参数的重载解析   由braced-init-list的元素组成,但有限制   只允许非缩小的转换

但是在这种情况下,复制构造函数被删除了,所以不应该通过重载分辨率选择它吗​​?

1 个答案:

答案 0 :(得分:6)

这是CWG 2327。就标准而言,您是正确的,但是一些编译器在这种情况下还考虑转换函数,因为这样做确实有意义。