Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

auto with parentheses and initialiser list

Coming up from another question:

Since C++17, auto x0{1, 2, 3, 4};, previously deducing an initialiser list, is not allowed any more (sure, we can use auto x0 = {1, 2, 3, 4}; instead...). Now as always avoiding uniform initialisation (e. g. std::vector<int> v({1, 2, 3, 4});, i. e. explicit constructor call with initialiser list as argument) and in analogy to the well defined auto x(7); (a construct I won't ever use myself either...), I came up with the following:

auto x({1, 2, 3, 4});
// -> std::initializer_list<int> x({1, 2, 3, 4});

This compiled with GCC 7.2.0 (mingw64), but issued a warning (while the commented version again did not):

list-initializer for non-class type must not be parenthesized

I couldn't find anything relevant in the standard, so now the question is (out of pure interest...):

Why is this not allowed? (Is this covered by the standard or do we need to consider this a GCC bug?)

like image 397
Aconcagua Avatar asked Jul 04 '18 09:07

Aconcagua


1 Answers

This is ill-formed. In short, braced-init-list can't be deduced in template argument deduction, it's considered as non-deduced context.

6) The parameter P, whose A is a braced-init-list, but P is not std::initializer_list or a reference to one:

Firstly, auto type deduction uses the rules of template argument deduction from a function call. [dcl.type.auto.deduct]/4

(emphasis mine)

If the placeholder is the auto type-specifier, the deduced type T' replacing T is determined using the rules for template argument deduction. Obtain P from T by replacing the occurrences of auto with either a new invented type template parameter U or, if the initialization is copy-list-initialization, with std​::​initializer_­list<U>. Deduce a value for U using the rules of template argument deduction from a function call, where P is a function template parameter type and the corresponding argument is e. If the deduction fails, the declaration is ill-formed. [ Example:

const auto &i = expr;

The type of i is the deduced type of the parameter u in the call f(expr) of the following invented function template:

template <class U> void f(const U& u);

— end example ]

Note that auto x({1, 2, 3, 4}); is direct initialization, not copy initialization, then the invented type template parameter is just U, not std​::​initializer_­list<U>, and the corresponding argument is {1, 2, 3, 4}.

And in template argument deduction from a function call, template parameter can't be deduced from braced-init-list. [temp.deduct.call]/1

Template argument deduction is done by comparing each function template parameter type (call it P) that contains template-parameters that participate in template argument deduction with the type of the corresponding argument of the call (call it A) as described below. If removing references and cv-qualifiers from P gives std​::​initializer_­list or P'[N] for some P' and N and the argument is a non-empty initializer list ([dcl.init.list]), then deduction is performed instead for each element of the initializer list, taking P' as a function template parameter type and the initializer element as its argument, and in the P'[N] case, if N is a non-type template parameter, N is deduced from the length of the initializer list. Otherwise, an initializer list argument causes the parameter to be considered a non-deduced context ([temp.deduct.type]). [ Example:

template<class T> void g(T);
g({1,2,3});                     // error: no argument deduced for T

— end example ]

like image 178
songyuanyao Avatar answered Nov 08 '22 11:11

songyuanyao