I am trying to migrate an old c 03 codebase to c 11. But I fails to understand what gcc is warning me about in the following case:
% g -std=c 03 t.cxx
% g -std=c 11 t.cxx
t.cxx: In function ‘int main()’:
t.cxx:8:21: warning: converting to ‘A’ from initializer list would use explicit constructor ‘A::A(int)’
8 | int main() { B b = {}; }
| ^
t.cxx:8:21: note: in C 11 and above a default constructor can be explicit
where
struct A {
explicit A(int i = 42) {}
};
struct B {
A a;
};
int main() {
B b = {};
return 0;
}
All I am trying to do is a basic zero initialization here. It seems to be legal for c 03 but I fail to understand how to express the equivalent in c 11.
For reference, I am using:
% g --version
g (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0
CodePudding user response:
Since B
is an aggregate class, the following rule from the C 11 draft standard applies [decl.init.aggr/7]:
If there are fewer initializer-clauses in the list than there are members in the aggregate, then each member not explicitly initialized shall be initialized from an empty initializer list ([dcl.init.list]).
b.a
is therefore initialized from an empty initializer list. But this can be performed in two different contexts [dcl.init.list/1]:
List-initialization can occur in direct-initialization or copy-initialization contexts; list-initialization in a direct-initialization context is called direct-list-initialization and list-initialization in a copy-initialization context is called copy-list-initialization.
In the direct-initialization context, everything is fine, as A a{};
is. However, in the copy-initialization context, it is not, as A a={};
is not.
GCC and Clang seemingly apply copy-initialization context here, while MSVC seems to apply direct-initialization context (at least, it does not emit any warnings nor errors).
Live demo: https://godbolt.org/z/1n66v1n5c
I am not sure which compiler is right, or if it is even specified which context should apply here. Since b
is copy-list-initialized, the copy initialization context makes more sense to me.
CodePudding user response:
The given program is ill-formed for the reason(s) explained below.
C 20
B
is an aggregate. Since you're not explicitly initializing a
, dcl.init.aggr#5 applies:
- For a non-union aggregate, each element that is not an explicitly initialized element is initialized as follows:
5.2 Otherwise, if the element is not a reference, the element is copy-initialized from an empty initializer list ([dcl.init.list]).
This means that a
is copy initialized from an empty initializer list.
In other word, it is as if we're writing:
A a = {}; //not valid see reason below
Note also that list-initialization in a copy initialization context is called copy-list-initialization which is the case here. And from over.match.list#1.2:
In copy-list-initialization, if an explicit constructor is chosen, the initialization is ill-formed.
Essentially, the reason for the failure is that A a = {};
is ill-formed.
C 11
Since B
is an aggregate and there are fewer initializer-clauses in the list than there are members in the aggregate, and from aggregate initialization documentation:
The effects of aggregate initialization are:
- If the number of initializer clauses is less than the number of members and bases (since C 17) or initializer list is completely empty, the remaining members and bases (since C 17) are initialized by their default member initializers, if provided in the class definition, and otherwise (since C 14) copy-initialized from empty lists, in accordance with the usual list-initialization rules (which performs value-initialization for non-class types and non-aggregate classes with default constructors, and aggregate initialization for aggregates).
This again means that a
is copy initialized from an empty list {}
. That is, it is as if you wrote:
A a = {}; //not valid see reason below
And from over.match.funcs:
In copy-list-initialization, if an explicit constructor is chosen, the initialization is ill-formed.
Note
Note that writing A a{};
on the other hand is well-formed as this is a direct-initialization context and so it is direct-list-initialization.