gcc 4.8.1中的C ++ 11:复制构造函数的列表初始化不起作用

时间:2013-10-01 09:19:41

标签: c++ gcc c++11 uniform-initialization

我鼓励这个问题: 如果我有

class A
{
public:
};
int main()
{
   A a{};
   A b{a};
}

gcc给出:

  

moves.cc:在函数'int main()'中:   moves.cc:15:7:错误:'A'的初始化程序太多     A b {a};

但是当我使用A b(a)代替A b {a}时,所有编译都正确。如果我声明默认构造函数,它也会编译。为什么会这样呢?

3 个答案:

答案 0 :(得分:14)

该类是聚合,因此列表初始化将执行聚合初始化,并且不会考虑隐式声明的构造函数。

由于没有数据成员,因此只有空列表才能成为有效的聚合初始化程序。

  

但是当我使用A b(a)代替A b{a}时,所有编译都正确。

直接初始化将使用隐式构造函数而不是尝试聚合初始化。

  

如果我声明默认构造函数,它也会编译。

通过声明构造函数,该类不再是聚合,只能使用构造函数初始化。

答案 1 :(得分:9)

如果没有定义自己的构造函数 class A将被视为聚合(即普通旧数据)存储类型。

在处理聚合时, list-initialization 不会考虑任何隐式声明的构造函数,而是会尝试直接初始化对象的成员。

如果A b { a } A是聚合,编译器将尝试使用A的值初始化a中的第一个成员;这当然会失败,因为A不包含任何成员。


标准说什么?

  

<强> [8.5.1 Aggregates]

  

1)聚合是一个没有用户提供的数组或类(第9条)   构造函数(12.1),没有用于非静态的大括号或等于初始化程序   数据成员(9.2),没有私有或受保护的非静态数据成员   (第11条),没有基类(第10条),也没有虚函数   (10.3)。

  

2)当初始化列表初始化聚合时,如   在8.5.4中指定,初始化器的元素被视为   增加下标中聚合成员的初始值设定项   或会员订单。每个成员都是从中复制初始化的   相应的初始化子句。如果initializer-clause是   转换需要表达式和缩小转换(8.5.4)   表达方式,该程序是不正确的。

答案 2 :(得分:2)

GCC遵循标准,但这是一个已知的缺陷,请参阅core issue 1467。缺陷报告于2014年11月得到解决,GCC的下一个主要版本(2015年4月发布的5.1版)支持新行为。