在 C++11 中将大括号初始化列表分配给 STL 容器

Assigning a braced-init-list to STL containers in C++11

我注意到,除了初始化之外,我还可以将初始化列表分配给 STL 容器,例如 std::array 和 std::vector。例如:

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

int main()
{
    array<int, 4> arr;
    vector<int> vec(4);

    arr = {{1, 2, 3, 4}};
    vec = {4, 3, 2, 1};

    cout << "arr: ";
    for (auto elem : arr)
        cout << elem << " ";

    cout << "\nvec: ";
    for (auto elem : vec)
        cout << elem << " ";
    cout << endl;
}

我正在 Clang 3.8.0 上仅使用 -std=C++11 标志编译此代码。我试图辨别此行为是由 C++11 标准定义的,还是仅由编译器定义的。我一直在尝试通过标准的相关部分(以及 cppreference.com 当标准中的语言变得太复杂时)并且到目前为止已经想出了这个:

初始化器列表

5.17.9 - 括号初始化列表可能出现在由用户定义的赋值运算符定义的赋值的右侧

std::array

23.3.2.2: class 数组依赖于隐式声明的特殊成员函数...以符合容器要求

std::vector

vector& operator=( std::initializer_list ilist );

从 std::vector 的重载赋值运算符的语法来看,显然支持通过初始化列表进行赋值。所以我想知道将初始化列表传递给为 STL 容器隐式定义的重载赋值运算符(在我的示例中为 std::array)是否是定义的行为?作为奖励,std::array 是唯一具有隐式定义的重载赋值运算符的 STL 容器吗?

我在 SO 上查看了相关问题的答案,例如:

Error: Assigning to an array from an initializer list

但是,给出的答案与我从编译器获得的行为或我从标准中解释的行为不一致。此外,我正在寻找一个更普遍的问题的答案,而不仅仅是将列表初始值设定项分配给 std::array.

参见 defect #1527,它改变了 [expr.ass]/9 中的措辞,从 "an assignment defined by a user-defined assignment operator""an assignment to an object of class type" - 也就是说,运算符不必是 user-defined。我假设您使用的编译器已经解决了这个缺陷。

std::array 有 implicitly-defined copy-assignment operator=(const std::array&) - 这就是被调用的那个,参数是通过聚合初始化构造的 std::array 临时值。

没有为接受 initializer_list.

std::array 定义赋值运算符

然而,隐式定义的赋值运算符(它本身是一个 std::array)的 参数 可以构造初始化列表。这正是这里发生的事情。

请注意,这不适用于 built-in 数组,它们根本无法分配。