const auto std::initializer_list difference between Clang and GCC

GCC bug. [dcl.spec.auto]/p7 (quoting N4527):

When a variable declared using a placeholder type is initialized,
[…] the deduced return type or variable type is determined from the
type of its initializer. […] Otherwise, let T be the declared type
of the variable […]. If the placeholder is the auto
type-specifier, the deduced type is determined using the rules for template argument deduction. If the initialization is
direct-list-initialization […]. […] Otherwise, 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 (14.8.2.1), where P is a function template parameter
type and the corresponding argument is the initializer […]. If the
deduction fails, the declaration is ill-formed. Otherwise, the type
deduced for the variable or return type is obtained by substituting
the deduced U into P.

Thus, in const auto l2 = { 1, 2, 3 };, deduction is performed as if for the function template

template<class U> void meow(const std::initializer_list<U>);

given the call meow({1, 2, 3}).

Now consider the const-less case auto l3 = { 1, 2, 3 }; (which GCC correctly deduces as std::initializer_list<int>). Deduction in this case is performed as if for the function template

template<class U> void purr(std::initializer_list<U>);

given the call purr({1, 2, 3}).

Since top-level cv-qualification of function parameters are ignored, it should be obvious that the two deduction should yield the same type.


[temp.deduct.call]/p1:

Template argument deduction is done by comparing each function
template parameter type (call it P) with the type of the
corresponding argument of the call (call it A) as described below.
If P is a dependent type, removing references and cv-qualifiers from
P gives std::initializer_list<P'> […] for some P' […] and
the argument is a non-empty initializer list (8.5.4), 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.

Deducing P' (which is U) against 1, 2, or 3, all literals of type int, obviously yields int.

Leave a Comment