initializer_list and template type deduction
Solution 1
Your first line printme({'a', 'b', 'c'})
is illegal because the template argument T
could not be inferred. If you explicitly specify the template argument it will work, e.g. printme<vector<char>>({'a', 'b', 'c'})
or printme<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 because il
is considered to be of type std::initializer_list<char>
, and therefore the template argument to printme()
can be deduced.
The only "funny" part here is that auto
will pick the type std::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:
A function parameter for which the associated argument is an initializer list (8.5.4) but the parameter does not have std::initializer_list or reference to possibly cv-qualified std::initializer_list type. [Example:
template<class T> void g(T); g({1,2,3}); // error: no argument deduced for T
— end example ]
However with auto
, § 7.1.6.4/6 has explicit support for std::initializer_list<>
if the initializer is a braced-init-list (8.5.4), with
std::initializer_list<U>
.
Solution 2
You can also overload the function to explicitly take an argument of type initializer_list.
template<typename T>
void printme(std::initializer_list<T> t) {
for (auto i : t)
std::cout << i;
}
Solution 3
This is specifically covered under § 14.8.2.5/5
A function parameter for which the associated argument is an initializer list but the parameter does not have
std::initializer_list
or reference to possibly cv-qualifiedstd::initializer_list
type. [ Example:template<class T> void g(T); g({1,2,3}); // error: no argument deduced for T
—end example ]
To make it work, you can specify the template argument type explicitly.
printme<std::initializer_list<int>>( {1,2,3,4} );
Related videos on Youtube
4ZM
Updated on June 11, 2022Comments
-
4ZM almost 2 years
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'});
-
Walter over 11 years+1 I learned something. that elevates
std::initialiser_list<>
to something beyond an ordinary library function. -
4ZM over 11 yearsSure, but that would make the other versions fail, e.g.
printme(std::vector<char>({'a', 'b', 'c'}));
. Template specialization won't work here unfortunately. -
4ZM over 11 yearsOh, but that's great! Thank you. I thought I had tried this, but I was wrong. Template specialization works fine here. Since the function can be implemented in exactly the same way, all that remains is how to figure out how to make one of them call the other...
-
4ZM over 11 yearsJust for completeness. Here is a way to solve the problem: pastebin.com/huEGwnDt
-
4ZM over 11 yearsWorks fine. You can even improve on that solution by implementing perfect forwarding for the initializer_list like this: pastebin.com/1ttGniBH ?
-
Joseph Mansfield over 9 yearsDo we know why this is the case? It seems pretty strange to me that if I want to allow a template function (maybe a range-based algorithm) to take a initializer list argument, I have to provide an overload for
std::initializer_list
. -
dshepherd about 8 years@JosephMansfield I haven't managed to find a definitive answer but I suspect it's to do with braces being used for uniform initialization. The call
g({1, 2, 3})
could also be taken to meang(Foo(1, 2, 3))
whereFoo
is any class with a constructor taking three ints. -
김선달 almost 4 years@4ZM If you call without parameters, the call is ambiguous.