std::vector和std::array初始化列表的区别

7

这段C++11代码对我来说很有效:

#include <iostream>
#include <vector>
#include <array>
using namespace std;

struct str {
    int first, last;
};


vector<str> fields {
    {1,2}, {3,4}, {5,6}
};

int main()
{
    for (str s : fields)
        cout << s.first << " " << s.last << endl;
}

它打印出了六个预期的值。

但是,如果我将vector<str>更改为array<str,3>,gcc会给出以下错误:“std::array的初始值设定项过多”。

如果我这样改变fields的初始化:

array<str,3> fields {
    str{1,2}, str{3,4}, str{5,6}
};

事情进展得很顺利。

那么,在使用std::array时,为什么我需要使用str{1,2},而在使用std::vector时只需要{1,2}呢?

2个回答

6

请查看cppreference中聚合初始化一节。

聚合初始化的效果为:

  • 按照数组下标/出现顺序,每个数组元素或非静态类成员从初始化列表的相应子句中进行复制初始化。

  • 如果初始化子句是嵌套的花括号初始化列表,则相应的类成员本身是一个聚合:聚合初始化是递归的。

这意味着,如果您的结构体中有一个聚合体,例如:

struct str {
    struct asdf
    {
        int first, last;
    } asdf; 
};

asdf将由第一个嵌套的花括号初始化列表进行初始化,即{ { 1, 2 } }。通常需要两对大括号的原因是因为嵌套的花括号初始化列表初始化了std::array中的基础聚合体(例如,T a[N])。

但是,您仍然可以像这样初始化数组:

array<str,3> fields {
    1, 2, 3, 4, 5, 6
};

或者:

array<str,3> fields { {
    1, 2, 3, 4, 5, 6
} };

另一方面,如何初始化您的向量是由列表初始化覆盖的。std::vector有一个接受std::initializer_list的构造函数。

类型为T的对象的列表初始化的效果如下:

  • 否则,将考虑T的构造函数,分两个阶段:

    • 检查所有仅以std::initializer_list作为参数或作为其余参数具有默认值的第一个参数的构造函数,并通过重载解析匹配类型为std::initializer_list的单个参数

请注意,您将无法像这样初始化向量:

instead.

vector<str> fields {
    1,2, 3,4, 5,6
};

但是:

vector<int> fields {
    1,2, 3,4, 5,6
};

非常好。


4

这是因为数组初始化与向量不同。
要初始化一个数组,需要使用两个大括号。
由于语法特性,如果只初始化一个对象,可以省略它。
所以以下方式是正确的:

array{1,2,3} -> array{{1,2,3}}

但在你的示例中,您初始化了多个对象,因此编译器不会添加额外的大括号。使用两个大括号可以解决这个问题。

array<str,3> fields {{
    {1,2}, {3,4}, {5,6}
}};

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