dav*_*aja 13 c++ gcc stl clang c++11
我试图理解组合初始化列表和C++ 11时应该是什么样的正确行为const auto.我在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;
}
Run Code Online (Sandbox Code Playgroud)
用g ++编译输出是:
explicit: St16initializer_listIiE
auto: St16initializer_listIKiE
Run Code Online (Sandbox Code Playgroud)
而clang ++编译版本产生:
explicit: St16initializer_listIiE
auto: St16initializer_listIiE
Run Code Online (Sandbox Code Playgroud)
似乎GCC正在将这auto条线转变为std::initializer_list<const int>Clang生产的一段时间std::initializer_list<int>.当我使用它来初始化a时,GCC版本会产生问题std::vector.因此,以下在Clang下工作,但会为GCC产生编译器错误.
// Compiles under clang but fails for GCC because l4
std::vector<int> v2 { l2 };
Run Code Online (Sandbox Code Playgroud)
如果GCC正在生成正确的版本,那么它似乎建议应该扩展各种STL容器以包含这些情况的另一个列表初始化程序重载.
注意:这种行为在GCC(4.8,4.9,5.2)和Clang(3.4和3.6)的多个版本中似乎是一致的.
T.C*_*.C. 10
GCC错误.[dcl.spec.auto]/p7(引用N4527):
当初始化使用占位符类型声明的变量时,推导的返回类型或变量类型由其初始化程序的类型确定.[...]否则,让我们
T声明变量[...]的类型.如果占位符是auto类型说明符,则使用模板参数推导的规则确定推导的类型.如果初始化是 直接列表初始化 [...].[...]否则,通过用新发明的类型模板参数替换出现来获得P,或者如果初始化是 copy-list-initialization,则用.推断一个值TautoUstd::initializer_list<U>U使用函数调用中的模板参数推导规则(14.8.2.1),其中P是函数模板参数类型,相应的参数是初始化器[...].如果扣除失败,则声明格式不正确.否则,推断出该变量或返回类型的类型是由代推导得到U成P.
因此,在中const auto l2 = { 1, 2, 3 };,对功能模板执行推导
template<class U> void meow(const std::initializer_list<U>);
Run Code Online (Sandbox Code Playgroud)
接到电话meow({1, 2, 3}).
现在考虑无常量情况auto l3 = { 1, 2, 3 };(GCC正确推断为std::initializer_list<int>).在这种情况下的演绎就像执行功能模板一样
template<class U> void purr(std::initializer_list<U>);
Run Code Online (Sandbox Code Playgroud)
接到电话purr({1, 2, 3}).
由于忽略了函数参数的顶级cv限定,因此很明显两个推导应该产生相同的类型.
[temp.deduct.call]/P1:
模板参数推导是通过将每个函数模板参数类型(调用它
P)与调用的相应参数的类型(调用它)进行比较来完成的,A如下所述.如果P是一个依赖型,从除去引用和cv修饰符P给std::initializer_list<P'>[...]对于一些P'[...]和参数是一个非空的初始化列表(8.5.4),然后进行扣除,而不是为每个元素初始化列表,P'作为函数模板参数类型和初始化元素作为其参数.
推导P'(它是U)对1,2或3,类型的所有文字int,明显产生int.
有一个gcc错误报告错误自动从braced-init-list中扣除了关于这个和类似的案例,Richard Smith表示它是一个gcc bug:
更简单的测试用例:
Run Code Online (Sandbox Code Playgroud)#include <initializer_list> const auto r = { 1, 2, 3 }; using X = decltype(r); using X = const std::initializer_list<int>;失败是因为
decltype(r)推断const std::initializer_list<const int>而不是const std::initializer_list<int>.
C++标准草案的部分是7.1.6.4 [dcl.spec.auto]部分,其中说:
当初始化使用占位符类型声明的变量,或者在使用包含占位符类型的返回类型声明的函数中发生return语句时,推导的返回类型或变量类型由其初始化程序的类型确定.[...]设T是函数的变量或返回类型的声明类型.如果占位符是自动类型说明符,则使用模板参数推导的规则确定推导的类型.[...]否则,通过用新发明的类型模板参数U替换auto的出现来获得P,或者如果初始化器是braced-init-list,则用std :: initializer_- list替换.使用函数调用中的模板参数推导规则(14.8.2.1)为U推导一个值,
Run Code Online (Sandbox Code Playgroud)auto x1 = { 1, 2 }; // decltype(x1) is std::initializer_list<int> auto x2 = { 1, 2.0 }; // error: cannot deduce element type- 示例] [示例:
Run Code Online (Sandbox Code Playgroud)const auto &i = expr;i的类型是下面发明的函数模板的调用f(expr)中参数u的推导类型:
Run Code Online (Sandbox Code Playgroud)template <class U> void f(const U& u);- 末端的例子]
| 归档时间: |
|
| 查看次数: |
1467 次 |
| 最近记录: |