std::vector和std::array初始值设定项列表之间的区别

Difference between std::vector and std::array initializer lists

本文关键字:std 列表 区别 之间 vector array      更新时间:2023-10-16

这段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}呢?

请参阅cppreference关于聚合初始化的部分。

聚合初始化的影响是:

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

  • 如果初始值设定项子句是嵌套的支撑init列表,那么相应的类成员本身就是一个聚合:聚合初始化是递归的。

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

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

asdf将由第一个嵌套的括号初始化列表(即{ { 1, 2 } })初始化。通常需要两对大括号的原因是嵌套的大括号init列表初始化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
} };

相反。

另一方面,列表初始化涵盖了如何初始化向量。CCD_ 12具有接受CCD_ 13的构造函数。

T类型对象的列表初始化的效果是:

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

    • std::initializer_list作为唯一参数的所有构造函数,或者如果其余参数具有默认值,由过载分辨率检查和匹配针对std::initializer_list类型的单个参数

请注意,您将无法初始化矢量(如下图所示:

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

但是:

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

非常好。

这是因为数组初始化的构建与向量有点不同
要初始化数组,需要使用两个大括号
由于语法特性,如果只初始化一个对象,则可以跳过它
所以以下是可以的:

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

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

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