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

Why is this direct initialization valid? (C++ 17)

本文关键字:C++17 有效 初始化 为什么      更新时间:2023-10-16

考虑以下两个类:

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;

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

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

但是,为什么这种直接列表初始化也可以编译?

A a;
B b{ a };

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

如果前一阶段未产生匹配项,则 T 的所有构造函数 参与针对以下参数集的重载解析 由大括号初始化列表的元素组成,但有限制 只允许非缩小范围的转换

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

这是CWG 2327。就标准而言,您是正确的,但是一些编译器也在此上下文中考虑了转换函数 - 因为它确实有意义。