I understand that, given a braced initializer, auto
will deduce a type of std::initializer_list
, while template type deduction will fail:
auto var = { 1, 2, 3 }; // type deduced as std::initializer_list<int>
template<class T> void f(T parameter);
f({ 1, 2, 3 }); // doesn't compile; type deduction fails
I even know where this is specified in the C++11 standard: 14.8.2.5/5 bullet 5:
[It's a non-deduced context if the program has] 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 void g(T);
g({1,2,3}); // error: no argument deduced for T
—end example ]
What I don't know or understand is why this difference in type deduction behavior exists. The specification in the C++14 CD is the same as in C++11, so presumably the standardization committee doesn't view the C++11 behavior as a defect.
Does anybody know why auto
deduces a type for a braced initializer, but templates are not permitted to? While speculative explanations of the form "this could be the reason" are interesting, I'm especially interested in explanations from people who know why the standard was written the way it was.
First of all it's "speculative explanations of the form "this could be the reason"" as you call it.
{1,2,3}
is not onlystd::initializer_list<int>
but also allow initialize types without constructor. For example:is correct code. To show that it isn't
initializer_list
let's see the following code:Error is:
And now to the question "What is the difference?"
in
auto x = {1, 2, 3};
code it's OK to determine type, because coder explicitly said "It's not important what's type it is" usingauto
While in case of function template he may be sure that he is using different type. And it's good to prevent errors in ambiguous cases (It doesn't seem like C++ style , through).
Especially bad it will be in case when there was 1 function
f(x)
and then it was changed to template one. Programmer wrote to use it asx
, and after adding new function for other type it slightly change to call completely different one.There are two important reasons for templates not to do any deduction (the two that I remember in a discussion with the guy in charge)
Concerns about future language extensions (there are multiple meanings you could invent - what about if we wanted to introduce perfect forwarding for braced init list function arguments?)
The braces can sometimes validly initialize a function parameter that is dependent
If
T
would be deduced at the right side toinitializer_list<int>
but at the left side tovector<int>
, this would fail to work because of a contradictional argument deduction.The deduction for
auto
toinitializer_list<T>
is controversial. There exist a proposal for C++-after-14 to remove it (and to ban initialization with{ }
or{a, b}
, and to make{a}
deduce to the type ofa
).The reason is described in N2640:
For conclusion, the problem is that if we allow a {}-list to deduce against a plain type parameter
T
, then the function with parameterT
would have very high priority during overload resolution, which may cause wired behavior (like the examples above).