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

oz1*_*1cz 7 c++ arrays stdvector initializer-list c++11

这个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;
}
Run Code Online (Sandbox Code Playgroud)

它打印出六个预期值.

但是,如果我vector<str>改为array<str,3>,gcc会给我这个错误:"std :: array'的初始化程序太多了".

如果我改变了初始化fields:

array<str,3> fields {
    str{1,2}, str{3,4}, str{5,6}
};
Run Code Online (Sandbox Code Playgroud)

事情很顺利.

那么为什么我str{1,2}在使用时需要std::array,但仅{1,2}在使用时std::vector

小智 6

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

聚合初始化的效果是:

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

  • 如果initializer子句是嵌套的braced-init-list,则相应的类成员本身就是一个聚合:聚合初始化是递归的.

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

struct str {
    struct asdf
    {
        int first, last;
    } asdf; 
};
Run Code Online (Sandbox Code Playgroud)

asdf将由第一个嵌套的brace-init-list初始化,即{ { 1, 2 } }.你通常需要两对大括号的原因是因为嵌套的brace-init-list初始化了底层聚合std::array(例如T a[N]).

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

array<str,3> fields {
    1, 2, 3, 4, 5, 6
};
Run Code Online (Sandbox Code Playgroud)

要么:

array<str,3> fields { {
    1, 2, 3, 4, 5, 6
} };
Run Code Online (Sandbox Code Playgroud)

代替.

另一方面,列表初始化涵盖了如何初始化向量.std::vector有一个接受一个的构造函数std::initializer_list.

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

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

    • std::initializer_list作为唯一参数的所有构造函数,或者如果其余参数具有默认值,则作为第一个参数,将检查所有构造函数,并通过重载解析与单个参数类型进行匹配std::initializer_list

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

vector<str> fields {
    1,2, 3,4, 5,6
};
Run Code Online (Sandbox Code Playgroud)

但:

vector<int> fields {
    1,2, 3,4, 5,6
};
Run Code Online (Sandbox Code Playgroud)

很好.