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
Tis a reference type, a prvalue temporary of the type referenced byTis 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
Tis 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
explicitconstructor 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
Tmeans:
— ifTis a (possibly cv-qualified) class type (Clause 9) with a user-provided constructor (12.1), then the default constructor forTis called […];
2) [class.ctor]/4:
A default constructor for a class
Xis a constructor of classXthat can be called without an argument.