我试图了解在组合初始化列表和 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;
}
用 g++ 编译的输出是:
explicit: St16initializer_listIiE
auto: St16initializer_listIKiE
当 clang++ 编译版本产生:
explicit: St16initializer_listIiE
auto: St16initializer_listIiE
似乎 GCC 正在转向 auto
行变成 std::initializer_list<const int>
而 Clang 产生 std::initializer_list<int>
. GCC 版本在我使用它来初始化 std::vector
时会产生问题.所以下面的工作在 Clang 下,但为 GCC 产生编译器错误。
// Compiles under clang but fails for GCC because l4
std::vector<int> v2 { l2 };
如果 GCC 正在生成正确的版本,那么它似乎建议应该扩展各种 STL 容器以包含针对这些情况的另一个列表初始化程序重载。
注意:这种行为似乎在多个版本的 GCC(4.8、4.9、5.2)和 Clang(3.4 和 3.6)中是一致的。
最佳答案
海湾合作委员会错误。 [dcl.spec.auto]/p7(引用 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 theauto
type-specifier, the deduced type is determined using the rules for template argument deduction. If the initialization is direct-list-initialization [...]. [...] Otherwise, obtainP
fromT
by replacing the occurrences ofauto
with either a new invented type template parameterU
or, if the initialization is copy-list-initialization, withstd::initializer_list<U>
. Deduce a value forU
using the rules of template argument deduction from a function call (14.8.2.1), whereP
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 deducedU
intoP
.
因此,在 const auto l2 = { 1, 2, 3 };
, 推导就像函数模板一样执行
template<class U> void meow(const std::initializer_list<U>);
接到电话meow({1, 2, 3})
.
现在考虑无 const 的情况 auto l3 = { 1, 2, 3 };
(GCC 正确推断为 std::initializer_list<int>
)。这种情况下的推导就像函数模板一样执行
template<class U> void purr(std::initializer_list<U>);
接到电话purr({1, 2, 3})
.
由于函数参数的顶级 cv 限定被忽略,很明显这两个推导应该产生相同的类型。
[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 itA
) as described below. IfP
is a dependent type, removing references and cv-qualifiers fromP
givesstd::initializer_list<P'>
[...] for someP'
[...] and the argument is a non-empty initializer list (8.5.4), then deduction is performed instead for each element of the initializer list, takingP'
as a function template parameter type and the initializer element as its argument.
推导 P'
(这是 U
)反对 1
, 2
, 或 3
, 所有 int
类型的文字, 显然产量 int
.
关于c++ - const auto std::initializer_list Clang 和 GCC 的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37295129/