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

A. *_* S. 6 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();
   }
};
Run Code Online (Sandbox Code Playgroud)

我可以看到为什么这段代码编译得很好:

A a;
B b = a;
Run Code Online (Sandbox Code Playgroud)

遵循复制初始化的规则,对象"a"被转换为类型B的prvalue,因为在C++ 17中不再需要复制构造函数,所以没有错误:

如果T是类类型,并且其他类型的cv-nonqualified版本不是T或从T派生,或者如果T是非类型类型,但是other的类型是类类型,则是用户定义的转换序列可以检查从其他类型转换为T(或从T派生的类型,如果T是类类型并且转换函数可用),并通过重载决策选择最佳的类型.转换的结果,即prvalue临时(直到C++ 17)prvalue表达式(自C++ 17),如果使用转换构造函数,则用于直接初始化对象.最后一步通常是优化的,转换的结果直接在为目标对象分配的内存中构造,但是即使没有使用,也需要访问适当的构造函数(移动或复制).(直到C++ 17)

但是为什么这个直接列表初始化编译呢?

A a;
B b{ a };
Run Code Online (Sandbox Code Playgroud)

我在列表初始化中找不到任何措辞,说明编译器在这种情况下应该尝试将A转换为B. 只考虑构造函数的重载决策:

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

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

Bar*_*rry 7

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