Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is there difference between template and auto type deduction for std::initializer_list edge case? [duplicate]

In his CppCon 2014 talke "Type Deduction and Why You Care", Scott Meyers raises the question why there is a special rule about auto and braced initializers in the C++11/C++14 standard (his question starts at 36m05s).

The semantic of auto in combination with a braced-init-list is defined in §7.1.6.4/6.


I thought about it and could not come up with a use-case either. The closest thing that I have seen so far is one example where Bjarne Stroustrup used it.

In his Cpp 2014 talk "Make Simple Tasks Simple!", he 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 it is only a workaround. He mentioned that it should not be necessary. Instead he would prefer to directly pass the arguments to the function. So, it cannot really serve as a good motivation for auto and initializer lists.


My understanding of C++ is not deep enough to judge the downsides of allowing initializer-lists in Bjarne's example, as he proposes. Anyway, it would avoid the need for auto in that case.

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

like image 218
Philipp Claßen Avatar asked Oct 12 '14 22:10

Philipp Claßen


People also ask

What are the differences in type deduction for function template arguments and the auto keyword?

auto type deduction is usually the same as template type deduction, but auto type deduction assumes that a braced initializer represents a std::initializer_list , and template type deduction doesn't. auto in a function return type or a lambda parameter implies template type deduction, not auto type deduction.

What is auto type in C++?

The auto keyword in C++ automatically detects and assigns a data type to the variable with which it is used. The compiler analyses the variable's data type by looking at its initialization. It is necessary to initialize the variable when declaring it using the auto keyword.

When to use auto in C++?

The auto keyword is a simple way to declare a variable that has a complicated type. For example, you can use auto to declare a variable where the initialization expression involves templates, pointers to functions, or pointers to members.

What is type deduction?

Type inference or deduction refers to the automatic detection of the data type of an expression in a programming language. It is a feature present in some strongly statically typed languages.


2 Answers

The rationale is in N2640, which wanted to ban deduction of a plain type parameter from a braced initializer list 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 carved out a special exception for auto:

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

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

which was deemed desirable behavior since the very beginning of the EWG discussions about initializer lists. Rather than coming up with a clever deduction rule for a parameter type T matched with a {}-list (an option we pursued in earlier sketches and drafts of this paper), we now prefer to handle this with a special case for "auto" variable deduction when the initializer is a {}-list. I.e., for the specific case of a variable declared with an "auto" type specifier and a {}-list initializer, the "auto" is deduced as for a function f(initializer_list<T>) instead of as for a function f(T).

like image 95
T.C. Avatar answered Nov 10 '22 13:11

T.C.


Scott Meyers addressed the topic in a blog post: Why auto deduces std::initializer_list for a braced initializer

Like T.C.'s answer, it also refers to N2640. The special deduction rule has been added to allow code like this to work:

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

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

The short story is that N2640 proposed the special case that auto should deduce braced initializers as initializer_lists, without realizing that doing so broke uniform initialization (e.g. it makes int x{7}; and auto x{7}; very different). N3922 fixes that by (of course!) introducing another special case: single parameter braced initializers have their own rule.

Slightly more detail: N2640 tries to keep template argument deduction simple but attempts to allow a braced initializer to be passed to two or more functions via assigning it to an auto. This got turned into wording in N2672. Note that Stroustrup's previous design in N2532 allows deduction of initializer_lists for both unconstrained template parameters and auto, which is more consistent but also breaks uniform initialization.

None of this explains why N3922 didn't just remove the special case for auto. That wouldn't have resulted in silent changes to the meaning of code and would have simplified the language.

like image 30
Philipp Claßen Avatar answered Nov 10 '22 13:11

Philipp Claßen