Reputation: 145
I was playing with some useless code to understand initialization of member references, and bumped into this:
struct A {};
struct B
{
B() : a()
{
}
const A& a;
};
The code above gives the following error when compiled with gcc 4.9.2:
In constructor 'B::B()':
error: value-initialization of reference type 'const A&'
B() : a()
Which I understand.
But if I use uniform initialization in B's constructor's initializer list, like so:
struct A {};
struct B
{
B() : a{}
{
}
const A& a;
};
It compiles fine.
So the question is, why does the use of uniform initialization here change the compilation result?
I also tried this with Microsoft Visual C++ 2013. It does not compile either version of the code, with the same error message:
Error 3 error C2440: 'initializing' : cannot convert from 'int' to 'const A &
You can have a quick play with it here:
Upvotes: 9
Views: 3865
Reputation: 137310
GCC is correct in its interpretation of {}
. [dcl.init.list]/p3.8-9 (quoting N4296; earlier drafts has the same relative ordering of these two bullets):
List-initialization of an object or reference of type
T
is defined as follows:
[7 inapplicable bullets omitted]
Otherwise, if
T
is a reference type, a prvalue temporary of the type referenced byT
is copy-list-initialized or direct-list-initialized, depending on the kind of initialization for the reference, and the reference is bound to that temporary. [ Note: As usual, the binding will fail and the program is ill-formed if the reference type is an lvalue reference to a non-const type. —end note ]- Otherwise, if the initializer list has no elements, the object is value-initialized.
List-initializing the reference hits bullet 3.8, causing the construction of a temporary. The value-initialization case, in 3.9, doesn't apply.
Value-initialization of a reference is ill-formed ([dcl.init]/p9):
A program that calls for default-initialization or value-initialization of an entity of reference type is ill-formed.
However, as of N4296, per [class.base.init]/p8:
A temporary expression bound to a reference member in a mem-initializer is ill-formed.
This was added as a result of CWG issue 1696, which is a DR (defect report) against C++14.
Pre-CWG1696, the standard provided that (N4140 [class.temporary]/p5.1):
A temporary bound to a reference member in a constructor’s ctor-initializer (12.6.2) persists until the constructor exits.
which means that the reference will become dangling immediately after construction. This presumably motivated CWG1696's decision to disallow such bindings altogether.
Upvotes: 7