在 c++ 草案 n4606 [dcl.init] 17.6 中有一段关于保证复制省略:
- 如果目标类型是(可能是 cv 限定的)类类型:
- 如果初始化表达式是纯右值并且源类型的 cv 非限定版本与目标类是同一类,则初始化表达式用于初始化目标对象。[示例:
T x = T(T(T()));
调用T
默认构造函数进行初始化x
。—结束示例]- [...]
还有一个问答讨论它是如何工作的。
就我自己的理解而言,我引用的规则保证了当初始化表达式是纯右值并且源类型的 cv 非限定版本与目标类是同一类时,不应该涉及任何 ctor。因此无需检查是否存在复制或移动 ctor,这使得以下代码在 C++17 中是合法的:
struct A {
A() {}
A(A const &) = delete;
A(A &&) = delete;
};
A f() { return A(); } // it's illegal in C++14, and suppose to be legal in C++17
然而,让我抓狂的是我在 c++ 草案 n4606 的列表初始化部分找不到类似的规则。我发现的是 ([dcl.init.list] 3.6)
[...]
- 否则,如果
T
是类类型,则考虑构造函数。枚举适用的构造函数,并通过重载决议(13.3、13.3.1.7)选择最佳构造函数。如果需要缩小转换(见下文)来转换任何参数,则程序格式错误。[...]
由于列表初始化比我引用的第一条规则具有更高的优先级,因此当初始化程序是初始化程序列表时,我们应该考虑列表初始化部分中的规则。正如我们所见,在列表初始化类类型时会考虑构造函数T
。所以,继续前面的例子,将
A ff() { return {A()}; }
在 C++17 中合法吗?有人能找到标准草案在哪里指定保证复制省略在列表初始化中如何工作吗?