Reputation: 14603
If we contrast list initialization of an aggregate and direct initialization of an aggregate, if I don't specify initializers for all fields, then I suppose the following applies:
For a non-union aggregate, each element that is not an explicitly initialized element is initialized as follows:
- If the element has a default member initializer, the element is initialized from that initializer. (since C++11)
- Otherwise, if the element is not a reference, the element is copy-initialized from an empty initializer list.
- Otherwise, the program is ill-formed.
otherwise, if the destination type is a (possibly cv-qualified) aggregate class, it is initialized as described in aggregate initialization except that narrowing conversions are permitted, designated initializers are not allowed, a temporary bound to a reference does not have its lifetime extended, there is no brace elision, and any elements without an initializer are value-initialized.
My question is, what is the difference between copy initialization from an empty initializer list and value-initialization? Maybe a change of language would be in order?
Upvotes: 1
Views: 115
Reputation: 40881
One difference would be that value-initialization could not call an initializer-list constructor in the same way copy-init from {}
could:
struct A {
A(std::initializer_list<int>);
};
struct B {
int i;
A a;
};
B b1{ 1 }; // OK: `B{ 1, {} }`, or `B{ 1, A(std::initializer_list<int>{}) }`
// B b2(1); // Error: Cannot value-init an A, it has no default constructor
B b3(1, {}); // Works when copying from `{}`
It appears that GCC/MSVC don't implement this properly, but clang does: https://godbolt.org/z/nj1frf9xv
Upvotes: 3