复制省略在列表初始化中的应用,在标准文档中有明确说明吗?

14
[dcl.init]/17.6中,明确写道对于括号初始化的情况,会发生复制省略:
如果初始化表达式是prvalue,并且源类型的cv-unqualified版本与目标类相同,则使用初始化表达式来初始化目标对象。例如:T x = T(T(T()));调用T的默认构造函数来初始化x。
但是,在列表初始化的情况下,上述段落不适用,我没有找到类似的内容。请参见[dcl.init.list]
所以根据C++17标准,为什么在这种情况下T x{T(T())};会发生复制省略。

相关问题:https://stackoverflow.com/questions/68436137/is-move-elision-required-in-case-of-copy-list-initialization-in-c20请仅返回翻译后的文本。 - Fedor
1个回答

5
根据当前草案,这种情况下没有复制消除。
考虑以下例子:
#include <iostream>
#include <initializer_list>

struct S {
    S() {std::cout << "default\n";}
    S(const S&) {std::cout << "copy\n";}
    S(std::initializer_list<S>) {std::cout << "initializer list\n";}
};

int main()
{
    S s = S{S()};
}

根据核心语言问题2137,应选择以std::initializer_list作为参数的构造函数(Clang可能选择复制构造函数或执行复制省略,这是不正确的)。因此,应考虑使用构造函数进行列表初始化。
问题在于当选择复制/移动构造函数时,省略此复制/移动是合理的。实际上,核心语言问题2327已经解决了这个缺陷。

1
这真的很不幸,这个核心语言问题解决方案只涉及一个非常特殊的情况,并禁用了一个非常频繁的复制省略,这是每个人都期望的。这真的很糟糕!希望GCC和Clang都能在没有匹配的初始化程序列表构造函数的情况下进行复制省略。 - Oliv
我不明白。这似乎是针对initializer_list的特殊情况,但OP似乎在询问大括号初始化列表的一般情况。实际上,我认为OP引用的文本条件并不适用于您的示例,因为initializer_list<S>S不是相同类型。底线:您的示例并未证明此规则无法应用于大括号初始化列表。问题2327似乎也涉及略有不同的情况,即隐式用户定义转换。 - Arne Vogel
@ArneVogel 我的意思是一般情况下不能进行复制省略,否则特殊情况就无法正确处理。问题2327讨论的是一个更普遍的问题。您可以在这个答案中看到更多细节。 - xskxzr
仅供文档记录(因为我在其中浪费了时间,所以在您正在使用该委员会时,我分享它):GCC 7.3 如果存在 initializer_list 构造函数,则选择它,但如果不存在 init.list. 构造函数,则进行复制省略,而 Clang 不选择 initializer_list 构造函数,并始终省略复制构造函数,ICC 18 只有在不使用列表初始化时才省略复制构造函数,但如果存在 initializer_list 构造函数,则不会选择它,MSVC 19 似乎没有实现 C++17 prvalue。编译器资源网站 - Oliv

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接