更好地理解C++大括号初始化语法

3
为什么下面的代码是非法的?
for (int index=0; index<3; index++)
{
    cout << {123, 456, 789}[index];
}

虽然这样做可以正常工作:

for (int value : {123, 456, 789})
{
    cout << value;
}

在IDEOne中的代码:http://ideone.com/tElw1w


3
std::initializer_list有成员beginend,但没有operator[] - clcto
正如T.C.所提到的,{123, 456, 789}不是一种类型,也不是表达式 - 更进一步地说,decltype({1, 2, 3})被定义为不合法。一个例外是使用auto进行类型推导。 - HelloWorld
2个回答

5

虽然std::initializer_list不提供operator[],但它确实有重载的begin()end(),这是范围基于for所使用的。你实际上可以像这样索引到一个initializer_list

    for (int index=0; index<3; index++)
    {
        cout << begin({123, 456, 789})[index];
    }

1
请注意成本:每次迭代都会创建/销毁一个临时数组。对于非平凡类型,这会变得非常昂贵。 - T.C.
它必须将.data部分的整数复制到堆栈中吗?为什么?(或者更糟糕的是,它正在构造一个vector<int>或类似的东西吗?) - StilesCrisis
1
@StilesCrisis 标准规定:“从初始化列表构造类型为std::initializer_list<E>的对象,就好像实现分配了一个由N个类型为const E的临时数组组成的数组,其中N是初始化列表中元素的数量。该数组的每个元素都使用相应的初始化列表元素进行复制初始化,并构造std::initializer_list<E>对象以引用该数组。” - mattnewport
1
请注意“as if”部分。这取决于编译器。 - Karoly Horvath
很酷的是,看看一个合理的优化器是否知道如何将所有副本进行优化。 - StilesCrisis
显示剩余4条评论

2
一个像 {123, 456, 789} 这样的 大括号初始化列表 并没有自己的类型,也不能进行索引(事实上,它不能与大多数其他运算符一起使用)。
基于范围的 for 循环对此情况有特殊处理以使其工作。(严格来说,特殊处理是在它内部使用的 auto&& 中,从 大括号初始化列表 推导出一个 std::initializer_list。)

那么,在哪些情况下,花括号初始化列表是合法的? - StilesCrisis
@StilesCrisis 这里有一段很长的注释,在[dcl.init.list]/p1中进行了总结。这个答案中有一个引用。 - T.C.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接