clang++
does not ever allow default initialization of a const variable of class-type without a user-defined constructor; g++
is slightly less restrictive (see below). According to this answer, this is because POD types "are not initialized by default." If I understand correctly, this means that default-initialization does not invoke the default-constructor, nor does it invoke value-initialization, so the data members inside the POD type are not initialized. Of course it makes no sense to have a const POD type with uninitialized values in it, since they can never be initialized and therefore are not safe to use.
There are a few variants of this situation:
- The type is technically "POD", but contains no data members (only functions). (
clang++
does not treat this as a special case, nor, I think, does the standard, butg++
does allow it, even when the constructor is markedexplicit
.) - An empty constructor is defined using
{}
. (This is the recommended workaround on theclang
page describing the issue.) - The default constructor is declared
=default
. (C++11 onward; the type is still considered POD, so neither compiler nor the standard treat it as a special case.) - Aggregate initialization is explicitly invoked using
{}
, which (if I understand correctly) becomes value-initialization. (C++11 onward; both compilers—and, I think, the standard—allow this.)
In the first case, there can be no uninitialized members, so it's unclear why any instantiation of the class itself would ever be considered "uninitialized," regardless of whether or not it's const
. Since g++
allows this behavior, is it safe to use? Why is it prohibited by clang++
and the standard? (And are there any other cases where g++
allows POD-default-initialization where clang++
does not?)
In the second and third cases, the requirement of using {}
instead of =default
seems odd to me. EDIT: this question explains the difference quite well, so I've removed the part of the question asking about the distinction. (I still think it's a terribly confusing aspect of the language, though.)
Finally, will Foo f{}
always zero-initialize members of built-in type if Foo::Foo(void)
is {}
, =default
, or implicitly-declared?