1

The following declaration fails in clang 3.8.1 but seems to compile without error in other compilers tested (e.g. gcc 6.1, MSVC 2015, clang 3.9.1).

constexpr std::integral_constant<int,0> myConstant;

clang 3.8.1 gives:

error: default initialization of an object of const type 'const std::integral_constant<int, 0>' without a user-provided default constructor constexpr std::integral_constant<int,0> myConstant;

Whereas the following compiles correctly in all compilers tested:

constexpr std::integral_constant<int,0> myConstant = {};

What is going on here? (is the clang 3.8.1 error correct?)

If I define my own type, should I write a user-provided default ctor so that users can avoid typing ={} ?

Ross Bencina
  • 3,822
  • 1
  • 19
  • 33

2 Answers2

1

constexpr variables must be initialized. A declaration of the form Typename variablename; will perform default initialization on variablename.

Types which do not have a trivial default constructor will, under default initialization, be uninitialized. Normally that's fine.

But constexpr variables are not permitted to be uninitialized. Therefore, for types with trivial default constructors, you have to visibly initialize them. By doing = {} to the variable, you are causing it to be value initialized, which will zero out the object.

This should not be considered a problem. In general, you should always visibly initialize a constexpr variable, even if it's just with = {}. That way, it's clear to everybody what you're doing.

And no, you should not add default constructors to types just so that people can make constexpr variables of them without visibly initializing them. You should only add a user-provided default constructor to a type if the type needs one to do its job.


As for the compiler behavior, that's on them. Clang's behavior in 3.8.1 is correct with regard to the specification, so the others are incorrect.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • `std::integral_constant` has no value representation (it's an empty struct). Does your "you should always visibly initialize" rule still apply? – Ross Bencina Feb 17 '17 at 07:30
  • @RossBencina: "*std::integral_constant has no value representation*" The standard is quite clear that all `constexpr` variables "shall be initialized". Whether it has a value representation is not something the standard cares about. This is also true of any variable declared in a `constexpr` function. – Nicol Bolas Feb 17 '17 at 07:32
  • This answer does not currently address my question "What is going on here?" -- why is the behavior different between different compilers? which compiler is correct? – Ross Bencina Feb 17 '17 at 07:33
  • @RossBencina: I thought the answer to "which compiler is correct" would be obvious, given my explanation of what the *standard* requires. But I've made the answer more explicit. – Nicol Bolas Feb 17 '17 at 07:35
  • @RossBencina: Then it has a regression, since you stated that 3.8.1 worked (ie: gave an error). I have explained what the C++ standard says should happen. You can judge that against specific compiler versions and file bugs on them as needed. – Nicol Bolas Feb 17 '17 at 07:37
0

According to this answer: https://stackoverflow.com/a/28338265/2013747, whether ={} is needed is an open issue that clang and gcc originally chose to implement differently. Allowing ={} to be omitted appears to be the direction that is preferred by the CWG, and clang 3.9 changed policy to reflect that.

Quoting CWG active issue #253:

253. Why must empty or fully-initialized const objects be initialized?

[]

Paragraph 9 of 8.6 [dcl.init] says:

If no initializer is specified for an object, and the object is of (possibly >cv-qualified) non-POD class type (or array thereof), the object shall be >default-initialized; if the object is of const-qualified type, the underlying >class type shall have a user-declared default constructor. Otherwise, if no >initializer is specified for an object, the object and its subobjects, if any, >have an indeterminate initial value; if the object or any of its subobjects are >of const-qualified type, the program is ill-formed.

What if a const POD object has no non-static data members? This wording requires an empty initializer for such cases [...]

(Emphasis added.) The conclusion here is that for compatibility with older compilers, and strict adherence to the standard, ={} must be used unless there is a user-declared default ctor.

The old clang behavior resulted from the above conservative interpretation of the language specification. CWG August 2011 meeting resolved:

Notes from the August, 2011 meeting:

If the implicit default constructor initializes all subobjects, no initializer should be required.

Source: http://open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#253

As far as I know, this change has not yet been incorporated into any version of the C++ standard. Therefore, while omitting ={} will likely continue to compile, and may in future be officially supported by the standard, it is not currently part of the official ISO standard.

Community
  • 1
  • 1
Ross Bencina
  • 3,822
  • 1
  • 19
  • 33