35

Is it allowed in standard:

struct A
{
  int a = 3;
  int b = 3;
};

A a{0,1}; // ???

Is this class still aggregate? clang accepts this code, but gcc doesn't.

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
Bikineev
  • 1,685
  • 15
  • 20

1 Answers1

44

In C++11 having in-class member initializers makes the struct/class not an aggregate — this was changed in C++14, however. This is something I found surprising when I first ran into it, the rationale for this restriction is that in-class initializers are pretty similar to a user defined constructor but the counter argument is that no one really expects that adding in-class initializers should make their class/struct a non-aggregate, I sure did not.

From the draft C++11 standard section 8.5.1 Aggregates (emphasis mine going forward):

An aggregate is an array or a class (Clause 9) with no user-provided constructors (12.1), no brace-or-equal initializers for non-static data members (9.2), no private or protected non-static data members (Clause 11), no base classes (Clause 10), and no virtual functions (10.3).

and in C++14 the same paragraph reads:

An aggregate is an array or a class (Clause 9) with no user-provided constructors (12.1), no private or protected non-static data members (Clause 11), no base classes (Clause 10), and no virtual functions (10.3).

This change is covered in N3605: Member initializers and aggregates which has the following abstract:

Bjarne Stroustrup and Richard Smith raised an issue about aggregate initialization and member-initializers not working together. This paper proposes to fix the issue by adopting Smith's proposed wording that removes a restriction that aggregates can't have member-initializers.

This comment basically sums up the reluctance to allowing them to be aggregates:

Aggregates cannot have user-defined constructors and member-initializers are essentially some kind of user-defined constructor (element) (see also Core Defect 886). I'm not against this extension, but it also has implications on what our model of aggregates actually is. After acceptance of this extension I would like to know how to teach what an aggregate is.

The revised version N3653 was adopted in May 2013.

Update

emsr points out that G++ 5.0 now supports C++14 aggregates with non-static data member initializers using either std=c++1y or -std=c++14:

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

See it working live.

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
  • So it seems like it is problem of not full Standard support by gcc – Bikineev Nov 25 '14 at 03:56
  • @Bikineev hmmm, what version of `gcc` are you using? I can not reproduce using `-std=c++11` using `gcc` from `4.7` to `4.9`. Can you clarify your question, you said that `clang` accepts it, I guess you meant `gcc`? – Shafik Yaghmour Nov 25 '14 at 03:59
  • I use gcc 4.9.1. I meant gcc doesn't support this change from proposal. I get:"error: no matching function for call to 'A::A()'" – Bikineev Nov 25 '14 at 07:01
  • 1
    @Bikineev ok, so you must be using `-std=c+1y` which will work for `clang` but won't in `gcc`. I can not get this to work in `clang` using `-std=c++11`, which is correct. – Shafik Yaghmour Nov 25 '14 at 09:59
  • @Bikineev: You have to tell GCC which standard to use. Alas, indeed at least [GCC 4.9.0 doesn't support this in C++14 mode](http://coliru.stacked-crooked.com/a/75676726c087620c). – Lightness Races in Orbit Nov 25 '14 at 10:22
  • 1
    C++14 aggregate initiaizers were only just added to [gcc 5.0](https://gcc.gnu.org/gcc-5/changes.html). This feature will be available with -std=c++1y or -std=c++14. – emsr Nov 27 '14 at 00:19
  • @ShafikYaghmour thank you for such extensive response! – Bikineev Nov 29 '14 at 16:25