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?
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 ofA 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.
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.
[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.
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With