const auto std::initializer_list difference between Clang and GCC

后端 未结 2 1523
闹比i
闹比i 2020-12-04 01:23

I am trying to understand what the correct behavior of C++11 should be when combining initialization lists and const auto. I am getting different behavior betwe

相关标签:
2条回答
  • 2020-12-04 01:52

    There is a gcc bug report wrong auto deduction from braced-init-list about this and similar cases and Richard Smith indicates it is a gcc bug:

    Even simpler testcase:

    #include <initializer_list>
    const auto r = { 1, 2, 3 };
    using X = decltype(r);
    using X = const std::initializer_list<int>;
    

    fails because decltype(r) is deduced as const std::initializer_list<const int> rather than const std::initializer_list<int>.

    The section of the draft C++ standard would be section 7.1.6.4 [dcl.spec.auto] which says:

    When a variable declared using a placeholder type is initialized, or a return statement occurs in a function declared with a return type that contains a placeholder type, the deduced return type or variable type is determined from the type of its initializer. [...] Let T be the declared type of the variable or return type of the function. If the placeholder is the auto type-specifier, the deduced type is determined using the rules for template argument deduction. [...] Otherwise, obtain P from T by replacing the occurrences of auto with either a new invented type template parameter U or, if the initializer is a braced-init-list, with std::initializer_- list. 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 initializer is the corresponding argument [...] [ Example:

    auto x1 = { 1, 2 }; // decltype(x1) is std::initializer_list<int>
    auto x2 = { 1, 2.0 }; // error: cannot deduce element type
    

    —end example ] [ 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 ]

    0 讨论(0)
  • 2020-12-04 02:06

    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.

    0 讨论(0)
提交回复
热议问题