There are really two issues here: the numeric type conversion and template argument deduction.
The std::vector<double>
constructor is allowed to use the braced list (even of int
s) for its std::vector<double>(std::initializer_list<double>)
constructor. (Note, however, that std::initializer_list<int>
does not implicitly convert to std::initializer_list<double>
)
emplace_back()
cannot construct the element from the brace expression because it is a template that uses perfect forwarding. The Standard forbids the compiler to deduce the type of {0,0}
, and so std::vector<double>::emplace_back<std::initializer_list<double>>(std::initializer_list<double>)
does not get compiled for emplace_back({})
.
Other answers point out that emplace_back
can be compiled for an argument of type std::initializer_list<vector::value_type>
, but will not deduce this type directly from a {}
expression.
As an alternative to casting the argument to emplace_back
, you could construct the argument first. As pointed out in Meyers' Item 30 (Effective Modern C++), auto
is allowed to deduce the type of a brace expression to std::initializer_list<T>
, and perfect forwarding is allowed to deduce the type of an object whose type was deduced by auto
.
std::vector<std::vector<double> > vec;
auto double_list = {0., 0.}; // int_list is type std::initializer_list<int>
vec.emplace_back(double_list); // instantiates vec.emplace_back<std::initializer_list<double>&>
emplace_back
adds an element to vec
by calling std::vector<double>(std::forward<std::initializer_list<double>>(double_list))
, which triggers the std::vector<double>(std::initializer_list<double>)
constructor.
Reference: Section 17.8.2.5 item 5.6 indicates that the this is a non-deduced context for the purposes of template argument deduction under 17.8.2.1 item 1.
Update: an earlier version of this answer erroneously implied that std::initializer_list<int>
could be provided in place of std::initializer_list<double>
.