Why are the deductions of the “auto” and “pattern” types different for simplified initializers?

I understand that, given a strict initializer, auto will output the type std::initializer_list , while the output of the template type will not be executed:

 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 stated in the C ++ 11: 14.8.2.5/5 bullet 5 standard:

[This is not an output context if the program has] A function parameter for which the associated argument is a list of initializers (8.5.4), but the parameter does not have a std :: initializer_list or a reference to a possibly cv-qualified std :: initializer_list type. [Example:

void g (T) pattern;

g ({1,2,3}); // error: no argument is output for T

-end example]

What I do not know or do not understand is why this difference in behavior such as deduction exists. The specification on the C ++ 14 CD is the same as in C ++ 11, so it seems that the standardization committee does not see the behavior of C ++ 11 as a defect.

Does anyone know why auto infers a type for a simplified initializer, but templates are not allowed? Although speculative explanations of the form “this may be the reason” are interesting, I am particularly interested in explanations from people who know why the standard was written the way it was.

+14
c ++ c ++ 11
Jul 10 '13 at 23:29
source share
2 answers

There are two important reasons why templates do not draw any conclusions (two that I remember in a discussion with the responsible guy)

  • Concerned about future language extensions (there are a few meanings that you could think of), but what about if we want to introduce perfect call forwarding for arguments with argument arguments with extended functions?)

  • The brackets can sometimes correctly initialize a function parameter, depending on

 template<typename T> void assign(T &d, const T& s); 
 int main() { vector<int> v; assign(v, { 1, 2, 3 }); } 

If T will be displayed on the right side on initializer_list<int> , but on the left side on vector<int> , this will not work due to the conflicting output of the argument.

The output for auto - initializer_list<T> is controversial. There is a suggestion for C ++ - after-14, to remove it (and prohibit initialization with { } or {a, b} , and make {a} deduce type a ).

+13
Jul 12 '13 at 19:37
source share

First of all, these are “speculative explanations of the form,” this may be the reason, ”as you call it.

{1,2,3} not only std::initializer_list<int> , but also allows you to initialize types without a constructor. For example:

 #include <initializer_list> struct x{ int a,b,c; }; void f(x){ } int main() { f({1,2,3}); } 

- The correct code. To show that this is not initializer_list , you can see the following code:

 #include <initializer_list> struct x{int a,b,c;}; void f(x){ } int main() { auto il = {1, 2, 3}; f(il); } 

Mistake:

 prog.cpp: In function 'int main()': prog.cpp:10:9: error: could not convert 'il' from 'std::initializer_list<int>' to 'x' 

And now to the question "What is the difference?"

in auto x = {1, 2, 3}; enter the code OK to determine the type, because the encoder explicitly said: "It doesn’t matter which type" using auto

In the case of a function template, he can be sure that he is using a different type. And it’s good to prevent errors in ambiguous cases (this does not look like C ++ style, through).

This will be especially bad if there was 1 function f(x) , and then it was changed to a template one. The programmer wrote to use it as x , and after adding a new function for another type, it changed slightly to call a completely different one.

0
Jul 11 '13 at 20:50
source share



All Articles