来自未选择列表初始化的数组引用的构造函数

Constructor from a reference to array not selected for list initialisation

给定以下结构:

struct A {
    template<typename T, std::size_t N>
    A(T const(&array)[N]) {}

    template<typename T, std::size_t N>
    A& operator=(T const(&array)[N]) { return *this; }
 };

代码:

// a is of type A
a = {1, 2, 3, 4};

编译得很好,因为 std::initialiser_list 被隐式转换为数组引用。

然而,

A a {1, 2, 3, 4};
A a = {1, 2, 3, 4};

无法同时使用 Clang 和 GCC 进行编译。当我添加一个接受 std::initialiser_list<T> 的构造函数时,它会编译。

我错过了什么?

您只需要额外的大括号或括号:

A a{{1, 2, 3, 4}}; // ok
A b({1, 2, 3, 4}); // ok

原因是外层 braces/parens 用于 A,内层大括号用于列表初始化的 array 对象。

通过赋值,您不需要额外的圆括号或大括号,因为函数调用隐含了它们:

a = {1, 2, 3, 4};

相当于:

a.operator=({1, 2, 3, 4});

或多或少。


It does compile when I add a constructor that accepts a std::initialiser_list<T>.

详细说明列表初始化的工作原理。当您编写 A a{1, 2, 3, 4} 时,我们正在 首先 寻找一些 std::initializer_list<T> 构造函数(我们还没有,所以没有找到)和然后寻找一个我们可以用四个参数调用的构造函数(不存在)。添加额外的 ()s 或 {}s 意味着我们正在寻找一个可以使用 one 参数调用的构造函数,我们使用 1, 2 ,3, 4 对其进行初始化.

添加 std::initializer_list<T> 构造函数后,现在它就是第一阶段初始化的可行候选对象。


注意这个:

compiles just fine, since std::initialiser_list is implicitly converted to an array reference.

不对。这个问题的任何地方都没有 std::initializer_list{1, 2, 3, 4} 在 C++ 中是一件有趣的事情。它没有类型或任何东西。它只是一个 braced-init-list。它仅基于我们赋予它意义的上下文。在这种情况下,它不是转换为不同事物的事物……它只是数组初始化器的集合。