I got a class named Test with a const int member named a:
class Test {
public:
const int a;
};
Then I instantiate a object of Test named test:
Test test;
and got an reasonable compile error "error: uninitialized const member in ‘class Test’", but something strange happened when I do like this:
Test test = Test();
There is no compile error,what happened? Won't Test() invoke default constructor like Test test; does and then invoke the default copy constructor? The compiler I'm using is "gcc (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4" and the compiler is configured for c++11 mode.
The first initialization
Test test;
has always been ill-formed. Plainly speaking, you are not allowed to leave const objects uninitialized.
The second initialization
Test test = Test();
is well-formed in C++98, C++03 and possibly in C++11 (but see my P.S. below). Yet it is ill-formed in C++14 and later.
The relevant change is contained in the definition of value-initialization, performed in response to () initializer. In C++03 (and before) absence of user-defined default constructor caused value-initialization to ignore constructors entirely and work as a constructor-independent initialization mechanism. The Test() expression would produce a properly zero-initialized temporary object.
However, in C++14 a deleted default constructor is treated by value-initialization the same way as a user-defined one: value-initialization now has to use it and, obviously, fail, since it is deleted.
C++11 8.5 (n3242)
7 To value-initialize an object of type T means:
— if T is a (possibly
cv-qualified) class type (Clause 9) with a user-provided constructor
(12.1), then the default constructor for T is called (and the
initialization is ill-formed if T has no accessible default
constructor);
— if T is a (possibly cv-qualified) non-union class type
without a user-provided constructor, then the object is
zero-initialized and, if T’s implicitly-declared default constructor
is non-trivial, that constructor is called.
...
C++14 8.5 (n3690)
8 To value-initialize an object of type T means:
— if T is a (possibly
cv-qualified) class type (Clause 9) with either no default constructor
(12.1) or a default constructor that is user-provided or deleted, then
the object is default-initialized;
— if T is a (possibly cv-qualified)
class type without a user-provided or deleted default constructor,
then 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;
...
(Emphasis mine). Note the addition of the "or deleted" wording in the latter version, which transferred classes with deleted implicit default constructors from the second bullet point to the first one.
For this reason compilers reject the latter initialization code in C++14 mode (and accept it in C++98/C++03 modes).
In other words, the second initialization compiled in your case because your compiler apparently is configured for C++03 mode (or before).
P.S. It is quite possible (or even very likely) that my draft version of C++11 is outdated. I don't have the final version of C++11. It is likely that the final version of C++11 included the same wording as C++14. That would explain the behavior of those compilers that reject it in C++11 mode as well. In that case the separation line passes between C++03 and C++11.
Test test = Test();
There is no compile error,what happened?
Your compiler has a bug. The code is ill-formed. The default constructor of Test is implicitly deleted because it would be ill-formed - you can't default-initialize a const int. It was fixed in gcc 4.9 (I can't find a bug report for this).
You have to provide an initializer for the const member, whether via something like Test{4} or via a mem-initializer-list.
... then invoke the default copy constructor?
Technically, it would invoke the default move constructor, though that would be elided anyway.
Just tried visual studio gives error to both mentioned things.
Just need to use member initializer list as below
class Test {
public:
const int a;
Test():a (0)
{
}
};
int main()
{
Test test;
Test test2 = Test();
return 0;
}
Related
I have the code:
class A {
public:
A() = default;
private:
int i = 1;
};
int main() {
const A a;
return 0;
}
It compiles fine on g++ (see ideone), but fails on clang++ with error:
default initialization of an object of const type 'const A' requires a user-provided default constructor
I reported this issue on LLVM bug-tracker and got it INVALID.
I see it absolutly pointless to try to convince the clang developers. On the other side, I don't see the reason for such restriction.
Can anyone advise, if the C++11 Standard somehow implies this code to be invalid? Or should I just report a bug to g++? Or maybe there is enough freedom in language rules to handle this code in many ways?
N3797 §8.5/7 says:
If a program calls for the default initialization of an object of a const-qualified type T, T shall be a class type with a user-provided default constructor.
There's no further example or explanation of this. I agree it seems pretty bizarre. Furthermore the rule was updated in C++11 to be more restrictive than it was in C++03, when class types needed user-declared constructors. (Your constructor is user-declared.)
The workaround is be to ask for value initialization using {}, or use Dietmar's clever out-of-class inline definition.
GCC does provide a diagnosis (and quite a nice one, referring to the newer C++11 requirements) if you add another member without an initializer.
private:
int i = 1;
int j;
unmem.cpp:11:11: error: uninitialized const ‘a’ [-fpermissive]
const A a;
^
unmem.cpp:1:7: note: ‘const class A’ has no user-provided default constructor
class A {
^
unmem.cpp:3:5: note: constructor is not user-provided because it is explicitly defaulted in the class body
A() = default;
^
unmem.cpp:7:9: note: and the implicitly-defined constructor does not initialize ‘int A::j’
int j;
The GCC source refers to DR 253, Why must empty or fully-initialized const objects be initialized? This is an open issue in the standard, last updated in August 2011 (post-C++11) with this note:
If the implicit default constructor initializes all subobjects, no initializer should be required.
Therefore whereas Clang complies with C++11 (and will comply as-is with C++14), GCC is implementing the latest thinking of the standardization committee.
Filed a GCC bug. I predict that you'll need -pedantic to get a diagnosis when (and if) the bug is fixed.
Note that you can turn your class easily into one which has a user-defined default constructor:
class A {
public:
A();
private:
int i = 1;
};
inline A::A() = default;
According to 8.4.2 [dcl.fct.def.default] paragraph 4:
... A special member function is user-provided if it is user-declared and not explicitly
defaulted or deleted on its first declaration. ...
This implicitly states that a function which is not explicitly defaulted on its first declaration is not user-provided. In combination with 8.5 [dcl.init] paragraph 6
... If a program calls for the default initialization of an object of a const-qualified type T, T shall be a class type with a user-provided default constructor.
it seems clear that you cannot use a default constructor defaulted on its first declaration to initialize a const object. However, you can use a defaulted definition if it isn't the first declaration as is done in the code above.
Edit: The following is based on outdated information. I just went through N3797 and this is what I found:
§ 8.5/7 [dcl.init]
If a program calls for the default initialization
of an object of a const-qualified type T, T shall be a class type with
a user-provided default constructor.
Note the standard quote in the link below says user-declared.
The following program compiles in g++ but not clang++:
struct A {};
void f()
{
A const a;
}
And it might be related to this bug report where it was "fixed". g++ fails to compile it once it contains data members unless they're initialized. Note that int member = 1 will no longer make A a POD. Comparatively, clang++ rejects all permutations (empty classes and data members initialized or not.) For an interpretation of what the standard means by the following paragraph:
§ 8.5/9 [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.
See Why does C++ require a user-provided default constructor to default-construct a const object?. Supposedly the program is ill-formed if the object is of const-qualified POD type, and there is no initializer specified (because POD are not default initialized). Note how g++ behaves for the following:
struct A {int a;};
struct B {int a = 1;};
int main()
{
A a;
B b;
const A c; // A is POD, error
const B d; // B is not POD, contains data member initializer, no error
}
Since C++17, this code is correct, as is the similar code from this question:
struct MyClass1 { int i{}; };
struct MyClass2 { const MyClass1 m; };
MyClass2 a;
clang 8.0.0 rejects this latter code even with -std=c++17 which means that clang 8.0.0 has a bug.
In C++17 the following new text was added as [dcl.init]/7 (as per P0490R0 in response to DR 253):
A class type T is const-default-constructible if default-initialization of T would invoke a user-provided constructor of T (not inherited from a base class) or if
each direct non-variant non-static data member M of T has a default member initializer or, if M is of class type X (or array thereof), X is const-default-constructible,
if T is a union with at least one non-static data member, exactly one variant member has a default member initializer,
if T is not a union, for each anonymous union member with at least one non-static data member, exactly one non-static data member has a default member initializer, and
each potentially constructed base class of T is const-default-constructible.
If a program calls for the default-initialization of an object of a const-qualified type T , T shall be a const-default-constructible class type or array thereof.
Prior to C++17 there was no such text; an object defined as const must either have an initializer or a user-provided constructor. So, prior to C++17, clang was correct and g++ was bugged to accept the code without diagnostic.
I have the code:
class A {
public:
A() = default;
private:
int i = 1;
};
int main() {
const A a;
return 0;
}
It compiles fine on g++ (see ideone), but fails on clang++ with error:
default initialization of an object of const type 'const A' requires a user-provided default constructor
I reported this issue on LLVM bug-tracker and got it INVALID.
I see it absolutly pointless to try to convince the clang developers. On the other side, I don't see the reason for such restriction.
Can anyone advise, if the C++11 Standard somehow implies this code to be invalid? Or should I just report a bug to g++? Or maybe there is enough freedom in language rules to handle this code in many ways?
N3797 §8.5/7 says:
If a program calls for the default initialization of an object of a const-qualified type T, T shall be a class type with a user-provided default constructor.
There's no further example or explanation of this. I agree it seems pretty bizarre. Furthermore the rule was updated in C++11 to be more restrictive than it was in C++03, when class types needed user-declared constructors. (Your constructor is user-declared.)
The workaround is be to ask for value initialization using {}, or use Dietmar's clever out-of-class inline definition.
GCC does provide a diagnosis (and quite a nice one, referring to the newer C++11 requirements) if you add another member without an initializer.
private:
int i = 1;
int j;
unmem.cpp:11:11: error: uninitialized const ‘a’ [-fpermissive]
const A a;
^
unmem.cpp:1:7: note: ‘const class A’ has no user-provided default constructor
class A {
^
unmem.cpp:3:5: note: constructor is not user-provided because it is explicitly defaulted in the class body
A() = default;
^
unmem.cpp:7:9: note: and the implicitly-defined constructor does not initialize ‘int A::j’
int j;
The GCC source refers to DR 253, Why must empty or fully-initialized const objects be initialized? This is an open issue in the standard, last updated in August 2011 (post-C++11) with this note:
If the implicit default constructor initializes all subobjects, no initializer should be required.
Therefore whereas Clang complies with C++11 (and will comply as-is with C++14), GCC is implementing the latest thinking of the standardization committee.
Filed a GCC bug. I predict that you'll need -pedantic to get a diagnosis when (and if) the bug is fixed.
Note that you can turn your class easily into one which has a user-defined default constructor:
class A {
public:
A();
private:
int i = 1;
};
inline A::A() = default;
According to 8.4.2 [dcl.fct.def.default] paragraph 4:
... A special member function is user-provided if it is user-declared and not explicitly
defaulted or deleted on its first declaration. ...
This implicitly states that a function which is not explicitly defaulted on its first declaration is not user-provided. In combination with 8.5 [dcl.init] paragraph 6
... If a program calls for the default initialization of an object of a const-qualified type T, T shall be a class type with a user-provided default constructor.
it seems clear that you cannot use a default constructor defaulted on its first declaration to initialize a const object. However, you can use a defaulted definition if it isn't the first declaration as is done in the code above.
Edit: The following is based on outdated information. I just went through N3797 and this is what I found:
§ 8.5/7 [dcl.init]
If a program calls for the default initialization
of an object of a const-qualified type T, T shall be a class type with
a user-provided default constructor.
Note the standard quote in the link below says user-declared.
The following program compiles in g++ but not clang++:
struct A {};
void f()
{
A const a;
}
And it might be related to this bug report where it was "fixed". g++ fails to compile it once it contains data members unless they're initialized. Note that int member = 1 will no longer make A a POD. Comparatively, clang++ rejects all permutations (empty classes and data members initialized or not.) For an interpretation of what the standard means by the following paragraph:
§ 8.5/9 [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.
See Why does C++ require a user-provided default constructor to default-construct a const object?. Supposedly the program is ill-formed if the object is of const-qualified POD type, and there is no initializer specified (because POD are not default initialized). Note how g++ behaves for the following:
struct A {int a;};
struct B {int a = 1;};
int main()
{
A a;
B b;
const A c; // A is POD, error
const B d; // B is not POD, contains data member initializer, no error
}
Since C++17, this code is correct, as is the similar code from this question:
struct MyClass1 { int i{}; };
struct MyClass2 { const MyClass1 m; };
MyClass2 a;
clang 8.0.0 rejects this latter code even with -std=c++17 which means that clang 8.0.0 has a bug.
In C++17 the following new text was added as [dcl.init]/7 (as per P0490R0 in response to DR 253):
A class type T is const-default-constructible if default-initialization of T would invoke a user-provided constructor of T (not inherited from a base class) or if
each direct non-variant non-static data member M of T has a default member initializer or, if M is of class type X (or array thereof), X is const-default-constructible,
if T is a union with at least one non-static data member, exactly one variant member has a default member initializer,
if T is not a union, for each anonymous union member with at least one non-static data member, exactly one non-static data member has a default member initializer, and
each potentially constructed base class of T is const-default-constructible.
If a program calls for the default-initialization of an object of a const-qualified type T , T shall be a const-default-constructible class type or array thereof.
Prior to C++17 there was no such text; an object defined as const must either have an initializer or a user-provided constructor. So, prior to C++17, clang was correct and g++ was bugged to accept the code without diagnostic.
To start with, I have a struct with one value with a default value
struct S {
int a = 1;
};
This type can be default constructed when it is non-const / non-constexpr by both gcc and clang. Under both, std::is_pod<S>::value is false. The weird behavior is as follows:
S s1; // works under both
const S s2{}; // works under both
const S s3; // only works in gcc, clang wants a user-provided constructor
None of the following attempts makes a difference to clang:
struct S {
int a = 1;
constexpr S() = default; // defaulted ctor
virtual void f() { } // virtual function, not an aggregate
private:
int b = 2; // private member, really not an aggregate
};
The only thing I can do that makes this work is to add constexpr S() { } explicitly. It seems really wrong to me that const S s; fails while const S s{}; especially when the type is not an aggregate.
The standard makes me think that Clang is right
N4296: 8.5/7
If a program calls for the default initialization of an object of a
const-qualified type T, T shall be a class type with a user-provided
default constructor
So why does gcc allow this, and is S{}; not default initializing, even when the type is not a POD or an aggregate?
const S s3;
Is covered by [dcl.init]/12:
If no initializer is specified for an object, the object is default-initialized.
Thus, as required by your quote, a user-provided default constructor must be present. Adding one like so
struct S {
int a = 1;
constexpr S(){}
};
then makes the declaration compile fine.
[..] especially when the type is not an aggregate.
S is an aggregate in your case, and the reason why const S s{} is valid. Aggregate initialization is applied for const S s{}, and everything's fine.
If S is not an aggregate,
List-initialization of an object or reference of type T is defined as
follows:
If T is an aggregate, aggregate initialization is performed (8.5.1).
Otherwise, if the initializer list has no elements and T is a class type with a default constructor, the object is value-initialized.
Now consider the definition of value initialization:
To value-initialize an object of type T means:
if T is a
(possibly cv-qualified) class type (Clause 9) with either no default
constructor (12.1) or a default constructor that is user-provided or deleted, then the object is default-initialized;
if T is a (possibly
cv-qualified) class type without a user-provided or deleted default
constructor, then
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;
The default ctor is indeed nontrivial since a member has got an initializer ([class.ctor]/4.9), but that's irrelevant since the constraints are checked eitherway. Hence default-initialization it is, and the line
const S s{};
Is just as valid (or invalid!) as
const S t;
So why does gcc allow this
Well:
Speaking in terms of the current standard, GCC is not compliant; See above.
There is an active CWG issue, #253, created fifteen years ago, that covers a similar scenario. The final note on this one from a 2011 meeting says
If the implicit default constructor initializes all subobjects, no initializer should be required.
That is the case with the implicit default constructor for S, and this would make all your lines valid.
GCC developers (e.g. here) implied that since the committee basically agreed upon that above resolution, the current behavior of GCC is feasible and should not be adjusted. So one could well argue that GCC is right and the standard is broken.
So it looks like gcc is basing this on DR 253 even though this is not resolved yet. We can see this from the the following gcc bug report which says:
This is by design, because as DR 253 shows, the normative standard is flawed.
and the gcc change that brought this into effect says:
Core 234 - allow const objects with no initializer or
user-provided default constructor if the defaulted constructor
initializes all the subobjects.
So technically clang is correct and gcc is not conformant but it seems like they believe DR 253 will be resolved in their favor. This makes complete sense if the main concern is indeterminate initial value which as far as I can tell it is. This change is documented in gcc 4.6 release notes:
In 4.6.0 and 4.6.1 G++ no longer allows objects of const-qualified
type to be default initialized unless the type has a user-declared
default constructor. In 4.6.2 G++ implements the proposed resolution
of DR 253, so default initialization is allowed if it initializes all
subobjects. Code that fails to compile can be fixed by providing an
initializer e.g.
struct A { A(); };
struct B : A { int i; };
const B b = B();
I have the code:
class A {
public:
A() = default;
private:
int i = 1;
};
int main() {
const A a;
return 0;
}
It compiles fine on g++ (see ideone), but fails on clang++ with error:
default initialization of an object of const type 'const A' requires a user-provided default constructor
I reported this issue on LLVM bug-tracker and got it INVALID.
I see it absolutly pointless to try to convince the clang developers. On the other side, I don't see the reason for such restriction.
Can anyone advise, if the C++11 Standard somehow implies this code to be invalid? Or should I just report a bug to g++? Or maybe there is enough freedom in language rules to handle this code in many ways?
N3797 §8.5/7 says:
If a program calls for the default initialization of an object of a const-qualified type T, T shall be a class type with a user-provided default constructor.
There's no further example or explanation of this. I agree it seems pretty bizarre. Furthermore the rule was updated in C++11 to be more restrictive than it was in C++03, when class types needed user-declared constructors. (Your constructor is user-declared.)
The workaround is be to ask for value initialization using {}, or use Dietmar's clever out-of-class inline definition.
GCC does provide a diagnosis (and quite a nice one, referring to the newer C++11 requirements) if you add another member without an initializer.
private:
int i = 1;
int j;
unmem.cpp:11:11: error: uninitialized const ‘a’ [-fpermissive]
const A a;
^
unmem.cpp:1:7: note: ‘const class A’ has no user-provided default constructor
class A {
^
unmem.cpp:3:5: note: constructor is not user-provided because it is explicitly defaulted in the class body
A() = default;
^
unmem.cpp:7:9: note: and the implicitly-defined constructor does not initialize ‘int A::j’
int j;
The GCC source refers to DR 253, Why must empty or fully-initialized const objects be initialized? This is an open issue in the standard, last updated in August 2011 (post-C++11) with this note:
If the implicit default constructor initializes all subobjects, no initializer should be required.
Therefore whereas Clang complies with C++11 (and will comply as-is with C++14), GCC is implementing the latest thinking of the standardization committee.
Filed a GCC bug. I predict that you'll need -pedantic to get a diagnosis when (and if) the bug is fixed.
Note that you can turn your class easily into one which has a user-defined default constructor:
class A {
public:
A();
private:
int i = 1;
};
inline A::A() = default;
According to 8.4.2 [dcl.fct.def.default] paragraph 4:
... A special member function is user-provided if it is user-declared and not explicitly
defaulted or deleted on its first declaration. ...
This implicitly states that a function which is not explicitly defaulted on its first declaration is not user-provided. In combination with 8.5 [dcl.init] paragraph 6
... If a program calls for the default initialization of an object of a const-qualified type T, T shall be a class type with a user-provided default constructor.
it seems clear that you cannot use a default constructor defaulted on its first declaration to initialize a const object. However, you can use a defaulted definition if it isn't the first declaration as is done in the code above.
Edit: The following is based on outdated information. I just went through N3797 and this is what I found:
§ 8.5/7 [dcl.init]
If a program calls for the default initialization
of an object of a const-qualified type T, T shall be a class type with
a user-provided default constructor.
Note the standard quote in the link below says user-declared.
The following program compiles in g++ but not clang++:
struct A {};
void f()
{
A const a;
}
And it might be related to this bug report where it was "fixed". g++ fails to compile it once it contains data members unless they're initialized. Note that int member = 1 will no longer make A a POD. Comparatively, clang++ rejects all permutations (empty classes and data members initialized or not.) For an interpretation of what the standard means by the following paragraph:
§ 8.5/9 [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.
See Why does C++ require a user-provided default constructor to default-construct a const object?. Supposedly the program is ill-formed if the object is of const-qualified POD type, and there is no initializer specified (because POD are not default initialized). Note how g++ behaves for the following:
struct A {int a;};
struct B {int a = 1;};
int main()
{
A a;
B b;
const A c; // A is POD, error
const B d; // B is not POD, contains data member initializer, no error
}
Since C++17, this code is correct, as is the similar code from this question:
struct MyClass1 { int i{}; };
struct MyClass2 { const MyClass1 m; };
MyClass2 a;
clang 8.0.0 rejects this latter code even with -std=c++17 which means that clang 8.0.0 has a bug.
In C++17 the following new text was added as [dcl.init]/7 (as per P0490R0 in response to DR 253):
A class type T is const-default-constructible if default-initialization of T would invoke a user-provided constructor of T (not inherited from a base class) or if
each direct non-variant non-static data member M of T has a default member initializer or, if M is of class type X (or array thereof), X is const-default-constructible,
if T is a union with at least one non-static data member, exactly one variant member has a default member initializer,
if T is not a union, for each anonymous union member with at least one non-static data member, exactly one non-static data member has a default member initializer, and
each potentially constructed base class of T is const-default-constructible.
If a program calls for the default-initialization of an object of a const-qualified type T , T shall be a const-default-constructible class type or array thereof.
Prior to C++17 there was no such text; an object defined as const must either have an initializer or a user-provided constructor. So, prior to C++17, clang was correct and g++ was bugged to accept the code without diagnostic.
I'm trying to nail down the differences between N3337 §8.5p7 (C++11) and N3797 §8.5p8 (post C++11) that deal with value-initialization.
N3337 §8.5p7:
To value-initialize an object of type T means:
if T is a (possibly cv-qualified) class type (Clause 9) with a user-provided constructor (12.1), then the default constructor for T
is called (and the initialization is ill-formed if T has no accessible
default constructor);
if T is a (possibly cv-qualified) non-union class type without a user-provided constructor, then the object is zero-initialized and, if
T’s implicitly-declared default constructor is non-trivial, that
constructor is called.
if T is an array type, then each element is value-initialized;
otherwise, the object is zero-initialized.
An object that is value-initialized is deemed to be constructed and thus subject to
provisions of this International Standard applying to “constructed”
objects, objects “for which the constructor has completed,” etc., even
if no constructor is invoked for the object’s initialization.
N3797 §8.5p8:
To value-initialize an object of type T means:
if T is a (possibly cv-qualified) class type (Clause 9) with either no default constructor (12.1) or a default constructor that is
user-provided or deleted, then the object is default-initialized;
if T is a (possibly cv-qualified) class type without a user-provided or deleted default constructor, then 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.
An object that is value-initialized is deemed to be constructed and
thus subject to provisions of this International Standard applying to
“constructed” objects, objects “for which the constructor has
completed,” etc., even if no constructor is invoked for the object’s
initialization.
Given these two rules the snippet below should give different results:
#include <iostream>
struct Base {
int i;
Base(int i):i(i) {}
Base():i(10) {}
};
struct Derived : public Base {
int j;
Derived(int j):Base(j), j(j) {}
Derived()=default;
};
int main() {
Derived d{};
std::cout << "d.i = " << d.i << " " << "d.j = " << d.j << '\n';
}
as follows:
According to N3337, the default constructor for Derived is called, as Derived has a user-provided constructor. The default constructor for Derived calls Base default constructor, which initializes Derived::i = 10, leaving Derived::j unitialized.
From N3797, as Derived has no user-provided default constructor, nor a deleted default constructor, the second bullet point applies. That is, Derived is zero-initialized, i.e., both Derived::i and Derived::j are initialized with 0 and the object d is default-initialized, which leaves Derived::i = 10.
Although my knowledge of Unixes is minimum, I've been trying to replicate these two cases, using different flags for the compilers clang++ and g++, by trial and error, in Coliru, to no avail. The results so far, all printed d.i = 10 d.j = 0 without warnings.
The program in the OP cannot distinguish if d.j is being initialized to 0 or if it is uninitialized and coincidentally happens to be 0. This would be clear if the Derived object in question were to be created in memory that is already initialized to a known non-zero value, say with placement new:
Derived d{42}; // d.i and d.j are both 42.
::new (&d) Derived{}; // d.i is 0, d.j is 0 per N3797 or 42 per N3337.
As dyp says in his comment, compilers typically track changes due to defects in the standard (as opposed to new features) and include them in their support for a particular standard revision. There is likely no compiler that compiles exactly the language as specified in any given standard document given that the standards are constantly in flux. When you tell, e.g., clang 3.4 to compile C++11 the language it actually implements is "the portion of C++11 plus pertinent defect resolutions that we had implemented (IIRC all of it for 3.4) in time for the 3.4 release."
The particular change to the value-initialization wording that the OP asks about happened in the resolution of Core Working Group (CWG) Defect Report (DR) number 1301 which also addressed DR1324 and DR1368. As a defect resolution, compilers would then have reason to implement the change.
Analysis with various compilers and versions (mostly performed by the OP) demonstrates:
VS2013 has not implemented DR1301.
GCC 4.6.4 also has not.
GCC 4.7.3 has implemented DR1301.
GCC 4.8.1 implements DR1301 as well.
In summary, there's no way to force a compiler to perform exactly as specified, but we can usually determine what's going on anyway with some careful analysis.