C++ const auto std::初始化器\u Clang和GCC之间的列表差异

C++ const auto std::初始化器\u Clang和GCC之间的列表差异,c++,c++11,gcc,stl,clang,C++,C++11,Gcc,Stl,Clang,我试图理解当组合初始化列表和const auto时,C++11的正确行为应该是什么。对于以下代码,我发现GCC和Clang的行为有所不同,我想知道哪个是正确的: #include <iostream> #include <typeinfo> #include <vector> int main() { const std::initializer_list<int> l1 = { 1, 2, 3 }; const auto l2

我试图理解当组合初始化列表和
const auto
时,C++11的正确行为应该是什么。对于以下代码,我发现GCC和Clang的行为有所不同,我想知道哪个是正确的:

#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;
}
而clang++编译版本会产生:

explicit: St16initializer_listIiE
auto:     St16initializer_listIiE
似乎GCC正在将
auto
行变成
std::initializer\u list
,而Clang生成
std::initializer\u list
。GCC版本在我使用它初始化
std::vector
时产生了一个问题。因此,下面的代码在Clang下工作,但会为GCC生成一个编译器错误

// Compiles under clang but fails for GCC because l4
std::vector<int> v2 { l2 };
//在clang下编译,但在GCC中失败,因为l4
std::向量v2{l2};
如果GCC正在生成正确的版本,那么它似乎建议应该扩展各种STL容器,以包括针对这些情况的另一个列表初始值设定项重载

注意:在GCC的多个版本(4.8、4.9、5.2)和Clang(3.4和3.6)中,这种行为似乎是一致的。

有一个关于这种情况和类似情况的GCC错误报告,Richard Smith指出这是一个GCC错误:

更简单的测试用例:

#include <initializer_list>
const auto r = { 1, 2, 3 };
using X = decltype(r);
using X = const std::initializer_list<int>;
-结束示例][示例:

auto x1 = { 1, 2 }; // decltype(x1) is std::initializer_list<int>
auto x2 = { 1, 2.0 }; // error: cannot deduce element type
const auto &i = expr;
i的类型是以下发明函数模板调用f(expr)中参数u的推导类型:

template <class U> void f(const U& u);
模板空f(常量U&U);
-[结束示例]


GCC错误。[dcl.spec.auto]/p7(引用N4527):

初始化使用占位符类型声明的变量时, […]推导的返回类型或变量类型由 其初始值设定项的类型。[…]否则,将
T
作为声明的类型 变量[…]的。如果占位符是
自动
类型说明符,使用模板参数推断规则确定推断的类型。如果初始化是 直接列表初始化[…]。[…]否则,通过将出现的
auto
替换为新发明的 键入模板参数
U
或,如果初始化为 复制列表初始化,使用
std::initializer\u list
。使用模板参数推断规则从 函数调用(14.8.2.1),其中
P
是函数模板参数 类型,相应的参数是初始值设定项[…]。如果 扣除失败,声明格式错误。否则,类型 对于变量或返回类型,通过替换 将
U
导出为
P

因此,在
constautol2={1,2,3},将对函数模板执行推断

template<class U> void meow(const std::initializer_list<U>);
template<class U> void purr(std::initializer_list<U>);
给定调用
purr({1,2,3})

由于忽略了函数参数的顶级cv限定,因此很明显,这两种推导应产生相同的类型


[临时扣减呼叫]/p1:

模板参数推导是通过比较每个函数来完成的 模板参数类型(称之为
P
),类型为 调用的相应参数(称之为
A
),如下所述。 如果
P
是依赖类型,则从中删除引用和cv限定符
P
给出
std::initializer\u列表您可以检查
std::vector v2(l2.begin(),l2.end())initializer\u list
而不是
const initializer\u list
does
auto l3={1,2,3}未在gcc中推导相同的模板参数(
const int
)?正确
自动l3={1,2,3}
不会推断出与
const auto l2={1,2,3}相同的模板参数在gcc中。当我尝试它时,
typeid(l3).name()
产生
St16initializer\u listIiE
@T.C。感谢您的快速响应。感谢您的快速响应和到错误报告的链接。
template<class U> void purr(std::initializer_list<U>);