Why is there a special type inference rule for automatic and copied initializers in C ++ 11 / C ++ 14?

In his talk about CppCon 2014, “Type Subtraction and Why You Care,” Scott Meyers raises the question of why there is a special rule for auto and compressed initializers in the C ++ 11 / C ++ 14 standard (his question starts at 36m05s ).

The semantics of a car in combination with a bit-init list are defined in §7.1.6.4 / 6.


I thought about it and could not find a use case. The closest I've seen so far is one example where Bjarne Straustup used it.

In their Cpp 2014 they say "Making simple tasks easy!" , it once uses auto to capture initializers (but only as a workaround).

Here is the code (part of slide 30, at 37m10s ):

  // auto ss1 = collect({ 1, 2, 3, 4, 5, 6 }, odd); // error: Bummer! auto lst = { 1, 2, 3, 4, 5, 6 }; auto ss2 = collect(lst, odd); // {1,3,5} 

But note that this is just a workaround. He noted that this is not necessary. Instead, he would prefer to pass arguments to the function directly. Therefore, this may not serve as a good motivation for auto and initializer lists.


My understanding of C ++ is not deep enough to judge the lower bounds of the permissions of initializer lists in the Bjarne example, as he suggests. In any case, to avoid the need for auto in this case.

So, auto and the initializer list only a workaround for something that could be better solved? Or are there good examples where the additional rule of automatic deduction in §7.1.6.4 / 6 is useful?

+6
source share
2 answers

The rationale is in N2640 , which wanted to ban the output of a simple type parameter from the copied list of initializers in general:

 template<class T> void inc(T, int); // (1) template<class T> void inc(std::initializer_list<T>, long); // (2) inc({1, 2, 3}, 3); // Calls (2). (If deduction had succeeded // for (1), (1) would have been called — a // surprise.) 

But a special exception is thrown for auto :

On the other hand, being able to infer initializer_list<X> for T is attractive to:

 auto x = { 1, 1, 2, 3, 5 }; f(x); g(x); 

which was considered desirable behavior from the start of the EWG Discussion on Initializer Lists. Instead of coming up with a clever deduction rule for the parameter type T matched with {} -list (an option that we followed in earlier sketches and drafts of this article), we now prefer to handle this with a special case for the variable “auto” deduction, when the initializer is {} -list. Ie, for the specific case of a variable declared using an "auto" type specifier, and a {} -list initializer, "auto" is output as for f(initializer_list<T>) instead of f(T) .

+8
source
Scott Meyers touched on a blog topic: Why auto displays std :: initializer_list for a copied initializer

Similar to the TC response, it also applies to the N2640 . A special subtraction rule has been added that allows you to work with this code:

  auto x = { 1, 1, 2, 3, 5 }; f(x); g(x); 

In a blog post, Scott provides the following explanation from James Hopkin:

The story that the N2640 suggested a special case is that auto should output fixed initializers as initializer_lists, not realizing that this violates uniform initialization (for example, it distinguishes int x{7}; and auto x{7}; ). N3922 fixes this (of course!) By introducing another special case: initializers with one parameter have their own rule.

In a bit more detail: N2640 tries to keep the simple output of the template argument, but tries to allow the portable initializer for two or more functions by assigning it auto. It turned into a wording in N2672 . Please note that the previous Stroustrup project in N2532 allows initializer_lists to be output both for unlimited template parameters and for cars, which is more consistent, but also breaks uniform initialization.

None of this explains why the N3922 did not just delete the special case for the car. This would not lead to silent changes in the meaning of the code and simplify the language.

+2
source

Source: https://habr.com/ru/post/976649/


All Articles