Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
165 views
in Technique[技术] by (71.8m points)

c++ - const auto std::initializer_list difference between Clang and GCC

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 between GCC and Clang for the following code and would like to know which is the correct one:

#include <iostream>
#include <typeinfo>
#include <vector>

int main()
{
    const std::initializer_list<int> l1 = { 1, 2, 3 };
    const auto l2 = { 1, 2, 3 };

    std::cout << "explicit: " << typeid(l1).name() << std::endl;
    std::cout << "auto:     " << typeid(l2).name() << std::endl;
}

Compiled with g++ the output is:

explicit: St16initializer_listIiE
auto:     St16initializer_listIKiE

While the clang++ compiled version produces:

explicit: St16initializer_listIiE
auto:     St16initializer_listIiE

It seems that GCC is turning the auto line into a std::initializer_list<const int> while Clang produces std::initializer_list<int>. The GCC version creates a problem when I use it to initialize a std::vector. So the following works under Clang but produces a compiler error for GCC.

// Compiles under clang but fails for GCC because l4
std::vector<int> v2 { l2 };

If GCC is producing the correct version then it seems to suggest that the various STL containers should be extended to include another list initializer overload for these cases.

Note: this behavior seems to be consistent across multiple versions of GCC (4.8, 4.9, 5.2) and Clang (3.4 and 3.6).

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...