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?)
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 ]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With