理解对象初始化

Understanding object initialization

本文关键字:初始化 对象      更新时间:2023-10-16

我在初始化数组时不小心忘记写大括号:

struct A
{
    A() { std::cout << "A()" << std::endl; }
    A(int a) { std::cout << "A(" << a << ")" << std::endl; }
};
int main()
{
    A a[3] =  A(2), A(3);
}

输出:

A(2)
A(2)
A(2)
A(3)

就我所知,这是正确的。N4257::12.6.1/2:

大括号可以在任何聚合的初始化列表中省略如果聚合具有具有用户定义类型的类类型的成员转换

但是括号初始化有不同的副作用:
struct A
{
    A() { std::cout << "A()" << std::endl; }
    A(int a) { std::cout << "A(" << a << ")" << std::endl; }
};
int main()
{
    A a[3] = { A(2), A(3) };
}

输出:

A(2)
A(3)
A()

你不能解释一下这个区别吗?

N4527§8.5 [dcl.init]

17初始化式的语义如下:目标类型是对象或引用的类型初始化后,源类型是初始化表达式的类型。如果初始化式不是单个的(可能是表达式,则源类型未定义。

-(17.1)如果初始化式是(未加括号的)大括号初始化列表,则对象或引用被列表初始化(8.5.4)。

-(17.2)如果目的类型是引用类型,请参见8.5.3。

-(17.3)如果目标类型是字符数组、char16_t数组、char32_t数组或wchar_t的数组,初始化式为字符串字面值,参见8.5.2。

-(17.4)如果初始化式为(),则对象为值初始化。

-(17.5)否则,如果目标类型是数组,则程序是病态的。

A a[3] = A(2)属于(17.5),因此程序是病态的。显然,在这种情况下,g++有一个bug。Clang正确拒绝你的代码