具有非静态成员初始化器的类的 C++11 聚合初始化

Posted

技术标签:

【中文标题】具有非静态成员初始化器的类的 C++11 聚合初始化【英文标题】:C++11 aggregate initialization for classes with non-static member initializers 【发布时间】:2015-01-22 23:22:16 【问题描述】:

标准是否允许:

struct A

  int a = 3;
  int b = 3;
;

A a0,1; // ???

这个类仍然是聚合的吗? clang 接受此代码,但 gcc 不接受。

【问题讨论】:

【参考方案1】:

在 C++11 中,具有类内成员初始值设定项使结构/类不是聚合 - 然而,这在 C++14 中已更改。这是我第一次遇到它时感到惊讶的事情,这种限制的基本原理是类内初始化器与用户定义的构造器非常相似,但相反的论点是没有人真正期望添加类内初始化器应该使他们的类/结构是非聚合的,我肯定没有。

来自draft C++11 standard 部分8.5.1 聚合强调我的未来):

聚合是没有用户提供的数组或类(第 9 条) 构造函数(12.1),非静态没有大括号或等号初始值设定项 数据成员 (9.2),没有私有或受保护的非静态数据成员 (第 11 条),没有基类(第 10 条),没有虚函数 (10.3)。

在C++14 中,同一段内容如下:

聚合是没有用户提供的数组或类(第 9 条) 构造函数(12.1),没有私有或受保护的非静态数据成员 (第 11 条),没有基类(第 10 条),没有虚函数 (10.3)。

N3605: Member initializers and aggregates 涵盖了此更改,其摘要如下:

Bjarne Stroustrup 和 Richard Smith 提出了关于聚合的问题 初始化和成员初始化器不能一起工作。这 论文提议通过采用 Smith 提议的措辞来解决这个问题 消除了聚合不能具有的限制 成员初始化器

这条评论基本上总结了不愿意让它们成为聚合体:

聚合不能有用户定义的构造函数和 成员初始化器本质上是某种用户定义的 构造函数(元素)(另请参见核心缺陷 886)。我不反对这个 扩展,但它也对我们的模型有影响 聚合实际上是。接受此扩展后我会 想知道如何教授聚合是什么。

修改版N3653被May 2013采纳。

更新

emsr 指出G++ 5.0 now supports C++14 aggregates with non-static data member initializers 使用std=c++1y-std=c++14

struct A  int i, j = i; ;
A a =  42 ; // a.j is also 42

看到它在工作live。

【讨论】:

看来是gcc不完全支持标准的问题 @Bikineev 嗯,你使用的是哪个版本的gcc?我无法使用-std=c++11 使用gcc4.7 复制到4.9。你能澄清你的问题吗,你说clang接受它,我猜你的意思是gcc 我使用 gcc 4.9.1。我的意思是 gcc 不支持提案中的这种更改。我得到:“错误:没有匹配函数调用 'A::A()'” @Bikineev 好的,所以你必须使用-std=c+1y,它适用于clang,但不适用于gcc。我无法使用-std=c++11clang 中使用它,这是正确的。 C++14 聚合初始化器刚刚添加到 gcc 5.0。此功能将通过 -std=c++1y 或 -std=c++14 提供。

以上是关于具有非静态成员初始化器的类的 C++11 聚合初始化的主要内容,如果未能解决你的问题,请参考以下文章

C ++中的静态构造函数?我需要初始化私有静态对象

嵌套类的值初始化

C ++初始化对象的非静态成员数组

类的静态数据成员初始化问题

Java的静态块和初始化块分别何时执行?有啥区别?

在 C++0x 中,非静态数据成员初始化器会覆盖隐式复制构造函数吗?