Consider the function:
template<typename T>
void printme(T&& t) {
for (auto i : t)
std::cout << i;
}
or any other function that expects one parameter with a begin()/end() - enabled type.
Why is the following illegal?
printme({'a', 'b', 'c'});
When all these are legitimate:
printme(std::vector<char>({'a', 'b', 'c'}));
printme(std::string("abc"));
printme(std::array<char, 3> {'a', 'b', 'c'});
We can even write this:
const auto il = {'a', 'b', 'c'};
printme(il);
or
printme<std::initializer_list<char>>({'a', 'b', 'c'});
This is specifically covered under § 14.8.2.5/5
To make it work, you can specify the template argument type explicitly.
Your first line
printme({'a', 'b', 'c'})
is illegal because the template argumentT
could not be inferred. If you explicitly specify the template argument it will work, e.g.printme<vector<char>>({'a', 'b', 'c'})
orprintme<initializer_list<char>>({'a', 'b', 'c'})
.The other ones you listed are legal because the argument has a well-defined type, so the template argument
T
can be deduced just fine.Your snippet with
auto
also works becauseil
is considered to be of typestd::initializer_list<char>
, and therefore the template argument toprintme()
can be deduced.The only "funny" part here is that
auto
will pick the typestd::initializer_list<char>
but the template argument will not. This is because § 14.8.2.5/5 of the C++11 standard explicitly states that this is a non-deduced context for a template argument:However with
auto
, § 7.1.6.4/6 has explicit support forstd::initializer_list<>
You can also overload the function to explicitly take an argument of type initializer_list.