Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++11 in gcc 4.8.1: list-initialization for copy constructor doesn't work

I encourages with this problem: If I have

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

gcc gives:

moves.cc: In function ‘int main()’: moves.cc:15:7: error: too many initializers for ‘A’ A b{a};

But when I use A b(a) instead of A b{a} all compiles correctly. And if I declare default constructor it compiles too. Why does it work so?

like image 889
user2834162 Avatar asked Oct 01 '13 09:10

user2834162


3 Answers

The class is an aggregate, so list-initialisation will perform aggregate initialisation, and won't consider the implicitly-declared constructors.

Since there are no data members, only an empty list can be a valid aggregate initialiser.

But when I use A b(a) instead of A b{a} all compiles correctly.

Direct initialisation will use the implicit constructor rather than attempting aggregate initialisation.

And if I declare default constructor it compiles too.

By declaring a constructor, the class is no longer an aggregate, and can only be initialised using a constructor.

like image 181
Mike Seymour Avatar answered Nov 13 '22 19:11

Mike Seymour


When not defining your own constructors class A will be considered an aggregate (ie. plain-old-data) storage type.

When dealing with an aggregate, list-initialization won't consider any implicitly declared constructors, instead it will try to initialize the members of your object directly.

In the case of A b { a } where A is an aggregate the compiler will try to initialize the first member in A with the value of a; this will of course fail since A doesn't contain any members.


What does the standard say?

[8.5.1 Aggregates]

1) An aggregate is an array or a class (Clause 9) with no user-provided constructors (12.1), no brace-or-equal-initializer s 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).

2) When an aggregate is initialized by an initializer list, as specified in 8.5.4, the elements of the initializer are taken as initializers for the members of the aggregate, in increasing subscript or member order. Each member is copy-initialized from the corresponding initializer-clause . If the initializer-clause is an expression and a narrowing conversion (8.5.4) is required to convert the expression, the program is ill-formed.

like image 9
Filip Roséen - refp Avatar answered Nov 13 '22 20:11

Filip Roséen - refp


GCC was following the standard, but that was a known defect, see core issue 1467. The defect report was resolved in November 2014 and the new behaviour is supported in the next major release of GCC (version 5.1, released April 2015).

like image 2
Jonathan Wakely Avatar answered Nov 13 '22 19:11

Jonathan Wakely