Description
Full name of submitter (unless configured in github; will be published with the issue): Jiang An
Reference (section label): [dcl.init.general]
Link to reflector thread (if any):
Issue description:
-
A class may be default-initializable while having more than one default constructors. In such cases, implementations don't consider any unselected default constructors during value-initialization, and may perform zero-initialization.
This strategy is slightly different from [dcl.init.general]/9 which doesn't exclude unselected defaulted constructors. Perhaps zero-initialization is desired and [dcl.init.general]/9 should be modified to match implementations. -
[dcl.init.general]/(9.1.2) seemly indicates that if the default constructor is defaulted (not user-provided) and non-trivial, then the object is zero-initialized and then default-initialized. The current wording might have some drawbacks and lead to implement divergence:
- Some implementations (gcc, icc, and clang) only perform default-initialization in this case, while others (msvc) perform both operations.
- When the default constructor is trivial, it is unobservable whether it is called after zero-initialization, so perhaps the default-initialization can be performed unconditionally.
Example:
struct Foo {
int x;
Foo() = default;
template<class T>
Foo(T = T()) {} // user-provided, also a default constructor
};
template<int N>
struct Bar {
int y;
Bar() requires (N >= 0) = default;
Bar() requires (N < 0) {} // user-provided
};
static_assert(Foo().x == 0); // passes
static_assert(Bar<0>().y == 0); // passes if supported
struct Baz {
int z;
int w = 1;
Baz() = default; // non-trivial
};
static_assert(Baz().z == 0); // passes on msvc, fails on gcc, icc, and clang
Suggested resolution:
There are two mutually exclusive suggested resolutions. Option A exclusively selects zero-initialization or default-initialization (matching gcc etc.), while Option B sometimes perform both forms (matching msvc, seemly the status quo).
Option A:
Change [dcl.init.general]/(9.1) as indicated:
if
T
is a (possibly cv-qualified) class type ([class]), the semantic constraints for default-initialization are checked, and then
- if
there is no selected default constructor ([class.default.ctor]) for default-initialization, or the selected default constructor is non-trivial or deleted, then the object is default-initialized;T
has either no default constructor ([class.default.ctor]) or a default constructor that is user-provided or deleted- otherwise, the object is zero-initialized
and the semantic constraints for default-initialization are checked, and if;T
has a non-trivial default constructor, the object is default-initialized
Option B:
Change [dcl.init.general]/(9.1) as indicated:
if
T
is a (possibly cv-qualified) class type ([class]), the semantic constraints for default-initialization are checked, and then
- if
there is no selected default constructor ([class.default.ctor]) for default-initialization, or the selected default constructor is user-provided or deleted, then the object is default-initialized;T
has either no default constructor ([class.default.ctor]) or a default constructor that is user-provided or deleted- otherwise, the object is zero-initialized and
the semantic constraints for default-initialization are checked, and ifthen default-initialized;T
has a non-trivial default constructor, the object is