Consider the snippet:
#include
void foo(const std::unordered_map &) {}
int main()
{
foo({});
}
List-initialization for references is defined as follows, [dcl.init.list]/3:
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.
So your code fails because
std::unordered_map m = {};
fails. List-initialization for this case is covered through this bullet from [dcl.init.list]/3:
Otherwise, if the initializer list has no elements and
T
is a class type with a default constructor, the object is value-initialized.
So the object's default constructor will be called1.
Now to the crucial bits:
In C++11, unordered_map
had this default constructor2:
explicit unordered_map(size_type n = /* some value */ ,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
Clearly, calling this explicit
constructor through copy-list-initialization is ill-formed, [over.match.list]:
In copy-list-initialization, if an
explicit
constructor is chosen, the initialization is ill-formed.
Since C++14 unordered_map
declares a default constructor that is non-explicit:
unordered_map();
So a C++14 standard library implementation should compile this without problems. Presumably libc++ is already updated, but libstdc++ is lagging behind.
To value-initialize an object of type
T
means:
— ifT
is a (possibly cv-qualified) class type (Clause 9) with a user-provided constructor (12.1), then the default constructor forT
is called […];
2) [class.ctor]/4:
A default constructor for a class
X
is a constructor of classX
that can be called without an argument.