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
doesauto 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>);