Fed*_*dor 6 c++ initializer-list c++20
在下面的C ++程序20我把误一个额外的一对弯曲的括号{}中B{{{{A{}}}}}:
#include <iostream>
struct A
{
A() { std::cout << "A() "; }
A( A&& ) = delete;
~A() { std::cout << "~A() "; }
};
struct B { std::initializer_list<A> l; };
int main()
{
[[maybe_unused]] auto x = B{{{{A{}}}}};
std::cout << ". ";
}
Run Code Online (Sandbox Code Playgroud)
Clang 拒绝了它,但是出现了一个奇怪的错误:
错误:调用“const A”的已删除构造函数
但令我惊讶的是 GCC 接受了它(https://gcc.godbolt.org/z/aPWe13xfc)。
你能解释一下为什么 GCC 接受它(它如何处理额外的弯曲括号)?
B{\xe2\x80\xa6},由于初始值设定项列表的单个元素未指定且不是类型B(因为它根本没有类型),因此是聚合初始化 ([dcl.init.list]/3.4)。 因此是从;B::l复制初始化的 {{{A{}}}}它是 的特化std::initializer_list,因此 /3.6 和 /5 适用。const A创建一个“1 的数组”,并且{{A{}}}是其单个元素的初始值设定项。
因此我们可以将代码简化为
\nconst A a = {{A{}}};\nRun Code Online (Sandbox Code Playgroud)\n根本没有提及B,事实上,Clang 和 GCC 对这条线产生了同样的分歧。Clang 拒绝它似乎是正确的:初始化由 /3.7 发送到构造函数,并且显然没有可行的构造函数(因此出现有关删除的移动构造函数的错误)。
奇怪的是,删除此处(或原始版本中)额外的一对大括号会导致两个编译器都接受:
\nconst A a = {A{}};\nRun Code Online (Sandbox Code Playgroud)\n尽管事实上这A不是一个总数,所以 /3.7 仍然适用。据推测,两个编译器都过度热情地执行“保证复制省略”(尽管程度不同),将纯右值识别A{}为最终由其初始化的对象;然而,这只发生在 [dcl.init.general]/16.6.1 中,在本分析中从未发挥作用。
| 归档时间: |
|
| 查看次数: |
144 次 |
| 最近记录: |