Implementation divergence with const int i;
and mutable
const int i;
and mutable
While teaching the other day, I had just finished talking about one place in which C++ departs from its usual no-nannying philosophy: C++ prevents the programmer from writing
const int i;
“I just want an entity with decltype const int
! I don’t care about its value. I’m
just trying to test if f(i)
compiles when i
is const. I’m not going to read from i
.”
Unfortunately, both the paper standard and every implementation — Clang, GCC, MSVC, and ICC
respectively — forbid this construction.
error: default initialization of an object of const type
'const int'
error: uninitialized 'const i' [-fpermissive]
error C2734: 'i': 'const' object must be initialized
if not 'extern'
error: const variable "i" requires an initializer
(Incidentally, GCC, what happened to const i
’s type in that error message?)
The same thing applies to types with default-initialized int fields. For example,
struct A { int i; };
const A a;
Clang, GCC, MSVC, ICC?
error: default initialization of an object of const type
'const A' without a user-provided default constructor
error: uninitialized 'const a' [-fpermissive]
(MSVC: contented silence)
error: const variable "a" requires an initializer --
class "A" has no user-provided default constructor
We went on to talk about the opposite of const
, which is mutable
.
And then a student asked me a question I hadn’t thought of before.
Since
mutable
makes the field non-const
, does that mean it’s okay again to define it without an initializer?
That is:
struct B { mutable int i; };
const B b;
Clang, GCC, MSVC, ICC?
(Clang: contented silence)
error: uninitialized 'const b' [-fpermissive]
(MSVC: contented silence)
error: const variable "b" requires an initializer --
class "B" has no user-provided default constructor
It is not clear to me what the intended behavior of the core language is, here.
(Of course what I would like to happen is for C++ to stop its overparenting and eliminate the error even in the simplest case. This would also simplify the C++17 standard to the tune of one sentence. In fact, C++2a instead balloons that one sentence into a whole paragraph, with a cross-reference to CWG 253. WG21 never met a simplification they couldn’t turn into an opportunity for expansion! See also P1155 “More Implicit Moves” suggested wording versus what actually happened in C++2a.)
Intel ICC (which reports __EDG_VERSION__ == 500
) actually has another
interesting quirk: it seems to treat constructors implicitly generated due
to non-static data member initializers as fundamentally different animals
from regular defaulted constructors. That is, EDG produces a warning
(but not a hard error) for this code:
struct C { int i = 42; };
const C c;
Clang, GCC, MSVC, ICC?
(Clang: contented silence)
(GCC: contented silence)
(MSVC: contented silence)
warning #854: const variable "c" requires an initializer --
class "C" has no user-provided default constructor
Adding C() = default;
shuts up EDG’s warning.