C++ Logo

std-discussion

Advanced search

In value-initialization, why does a (unselected) user-provided or deleted default constructor prevent zero-init?

From: Tam S. B. <cpplearner_at_[hidden]>
Date: Sat, 12 Dec 2020 03:29:32 +0000
[dcl.init.general]/8: > To _value-initialize_ an object of type T means: > > - if T is a (possibly cv-qualified) class type ([class]), then > - if T has either no default constructor ([class.default.ctor]) or a default constructor that is user-provided or deleted, then the object is default-initialized; > - 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; > - if T is an array type, then each element is value-initialized; > - otherwise, the object is zero-initialized. Consider ``` template<bool Cond> struct A { A() = default; // #1 template<class=void> A() {} // #2 A() requires Cond = delete; // #3 int x; }; void f() { constexpr A<false> a = {}; static_assert(a.x == 0); } ``` Here `A` "has" a default constructor that is user-provided (#2) and one that is deleted (#3), although neither will be selected by overload resolution. Therefore, according to [dcl.init.general]/8, the variable `a` is *not* zero-initialized, and thus `a.x` has indeterminate value, which makes the static_assert invalid. That is, #2 and #3 affect the semantics of the code, even though they are not selected. This seems counter-intuitive and hard to learn, and disagrees with all compilers I tested (GCC/Clang/MSVC), which all accept the code, despite the existence of `#2` and `#3`.

Received on 2020-12-11 21:29:36