在下面的 C++20 程序中,我错误地添加了一对额外的弯曲大括号{}
in 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 << ". ";
}
Clang 拒绝了它,但出现了一个奇怪的错误:
错误:调用“const A”的已删除构造函数
但令我惊讶的是 GCC 接受了它(https://gcc.godbolt.org/z/aPWe13xfc https://gcc.godbolt.org/z/aPWe13xfc ).
您能否解释一下为什么 GCC 接受它(它如何处理额外的弯曲括号)?
B{…}
,因为初始值设定项列表的单个元素未指定且不是类型B
(因为它根本没有类型),是聚合初始化([dcl.init.list]/3.4)。B::l
因此是从复制初始化的{{{A{}}}}
;这是一个专业std::initializer_list
,因此 /3.6 和 /5 适用。一个“数组 1const A
“ 被创建,并且{{A{}}}
是其单个元素的初始值设定项。
因此我们可以将代码简化为
const A a = {{A{}}};
没有提及B
事实上,Clang 和 GCC 对这条线也产生了同样的分歧。 Clang 拒绝它似乎是正确的:初始化由 /3.7 发送到构造函数,并且显然没有可行的构造函数(因此出现有关删除的移动构造函数的错误)。
奇怪的是,删除此处(或原始版本中)额外的一对大括号会导致两个编译器都接受:
const A a = {A{}};
尽管事实上A
不是聚合,因此 /3.7 仍然适用。想必两个编译器都过度热情地执行“保证复制省略”(尽管程度不同),识别纯右值A{}
最终由它初始化一个对象;然而,这只发生在 [dcl.init.general]/16.6.1 中,在本分析中从未发挥作用。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)