从引用到数组的构造函数未选择用于列表初始化

时间:2019-02-03 21:11:43

标签: c++ c++17 list-initialization

给出以下结构:

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>的构造函数时,它确实会编译。

我想念什么?

1 个答案:

答案 0 :(得分:2)

您只需要多余的括号或括号即可。

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

这样做的原因是外部大括号/括号用于A,内部大括号用于列表初始化的array对象。

有了赋值,您就不需要多余的括号或花括号,因为它们仅在函数调用中隐含了:

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

等效于:

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

或多或少。


  

当我添加一个接受std::initialiser_list<T>的构造函数时,它确实会编译。

详细说明列表初始化的工作方式。当您编写A a{1, 2, 3, 4}时,我们首先要寻找某个std::initializer_list<T>构造函数(我们还没有找到,所以找不到它)的 ,然后寻找我们可以使用四个参数(不存在)调用的构造函数。添加额外的(){}意味着我们正在寻找可以用 one 自变量调用的构造函数,并用1, 2 ,3, 4进行初始化。

一旦添加了std::initializer_list<T>构造函数,现在这对于初始化的第一阶段是可行的选择。


请注意,

  

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

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