如何使用初始化列表构造 std::array 对象? [复制]

Posted

技术标签:

【中文标题】如何使用初始化列表构造 std::array 对象? [复制]【英文标题】:How to construct std::array object with initializer list? [duplicate] 【发布时间】:2011-10-17 03:31:18 【问题描述】:

可能重复:How do I initialize a member array with an initializer_list?

你可以用初始化列表构造一个 std::array 就好了:

std::array<int, 3> a = 1, 2, 3;  // works fine

但是,当我尝试将 std::initializer_list 构造为类中的数据成员或基对象时,它不起作用:

#include <array>
#include <initializer_list>

template <typename T, std::size_t size, typename EnumT>
struct enum_addressable_array : public std::array<T, size>

    typedef std::array<T, size> base_t;
    typedef typename base_t::reference reference;
    typedef typename base_t::const_reference const_reference;
    typedef typename base_t::size_type size_type;

    enum_addressable_array(std::initializer_list<T> il) : base_til 

    reference operator[](EnumT n)
    
        return base_t::operator[](static_cast<size_type>(n));
    

    const_reference operator[](EnumT n) const
    
        return base_t::operator[](static_cast<size_type>(n));
    
;

enum class E a, b, c;
enum_addressable_array<char, 3, E> ea = 'a', 'b', 'c';

gcc 4.6 的错误:

test.cpp: In constructor 'enum_addressable_array<T, size, EnumT>::enum_addressable_array(std::initializer_list<T>) [with T = char, unsigned int size = 3u, EnumT = E]':
test.cpp:26:55:   instantiated from here
test.cpp:12:68: error: no matching function for call to 'std::array<char, 3u>::array(<brace-enclosed initializer list>)'
test.cpp:12:68: note: candidates are:
include/c++/4.6.1/array:60:12: note: std::array<char, 3u>::array()
include/c++/4.6.1/array:60:12: note:   candidate expects 0 arguments, 1 provided
include/c++/4.6.1/array:60:12: note: constexpr std::array<char, 3u>::array(const std::array<char, 3u>&)
include/c++/4.6.1/array:60:12: note:   no known conversion for argument 1 from 'std::initializer_list<char>' to 'const std::array<char, 3u>&'
include/c++/4.6.1/array:60:12: note: constexpr std::array<char, 3u>::array(std::array<char, 3u>&&)
include/c++/4.6.1/array:60:12: note:   no known conversion for argument 1 from 'std::initializer_list<char>' to 'std::array<char, 3u>&&'

我怎样才能让它工作,以便我的包装类可以使用初始化列表进行初始化,如下所示:

enum_addressable_array<char, 3, E> ea = 'a', 'b', 'c';

【问题讨论】:

【参考方案1】:

std::array&lt;&gt; 没有采用 std::initializer_list&lt;&gt;(初始化列表构造函数)的构造函数,并且没有特殊的语言支持将 std::initializer_list&lt;&gt; 传递给类的构造函数以使其可以工作。所以这失败了。

为了让它工作,你的派生类需要捕获所有元素然后转发它们,一个构造函数模板:

template<typename ...E>
enum_addressable_array(E&&...e) : base_tstd::forward<E>(e)... 

请注意,在这种情况下您需要...,因为大括号省略(在您的情况下省略大括号)在该位置不起作用。它只允许在 T t = ... 形式的声明中。因为std::array&lt;&gt; 包含一个嵌入原始数组的结构,所以需要两级大括号。不幸的是,我认为 std::array&lt;&gt; 的确切聚合结构尚未指定,因此您需要希望它适用于大多数实现。

【讨论】:

Clang 抱怨输入应该是E&amp;&amp; ...e。 (有时,g++ 告诉我去杀人。) 这不会覆盖复制构造函数等吗?可以限制更多吗?比如template&lt;typename ...E, class = decltype(base_tstd::forward&lt;Args__&gt;(std::declval&lt;Args__&gt;()...)...&gt; enum_addressable_array(E&amp;&amp;...e) : base_tstd::forward&lt;E&gt;(e)... (我不能让它工作) @alfC 模板永远不会比隐式生成的特殊成员函数更好,因为它们是完全匹配的(即使它们被隐式或显式声明为已删除)。然而,棘手的部分是,如果您传入 enum_addressable_array &amp; 之类的内容,这将是一个更好的匹配(因此在重载解决方案中更受欢迎)。 我有一个问题。你说:Unfortunately, I believe that the exact aggregate structure of std::array&lt;&gt; is unspecified, so you will need to hope that it works on most implementations. 但是,根据en.cppreference.com/w/cpp/concept/SequenceContainer#cite_note-1 ,需要std::array 来支持braced-init-list 分配。这是否意味着您的解决方案必须按照 C++ 标准工作,并且您不必依赖实现细节?不过我是在问,并不是说它必须起作用:这种进步水平是我理解的前沿:) @gaazkam 需要支持= ... 初始化。但不需要支持= .. 初始化。然而,对于成员初始化器的情况,它只适用于后者。但是因为它不需要支持后者,而前者只需要支持= ... 语法,最终在成员初始化的情况下你没有可移植的语法。但是,我不了解规范的最新修订。也许他们现在也支持这个案子。【参考方案2】:

由于std::array 是一个包含聚合的结构(它本身不是聚合,并且没有采用std::initializer_list 的构造函数),因此您可以使用初始化列表初始化结构内的底层聚合使用这样的双括号语法:

std::array<int, 4> my_array = 1, 2, 3, 4;

请注意,这不是使用 std::initializer_list ... 这只是使用 C++ 初始化器列表来初始化 std::array 的可公开访问的数组成员。

【讨论】:

【参考方案3】:

std::array 没有采用std::initializer_list 的构造函数。这是一件好事,因为初始化列表可以大于数组的固定大小。

您可以通过测试初始化​​器列表不大于数组的大小,然后将初始化器列表的元素复制到std::arrayelems 成员与std::copy 来初始化它。

【讨论】:

以上是关于如何使用初始化列表构造 std::array 对象? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

如何通过可变参数模板将多个构造函数参数转发到数组初始值设定项列表?

编译器生成的默认构造函数是否会将std :: array中的指针初始化为nullptr?

初始化具有非默认构造函数的 std::array 项的更好方法?

为啥 std::array<std::pair<int,int>, 3> 不能使用嵌套初始化列表初始化,但 std::vector<std::pair<int,in

std::array 默认初始化还是值初始化?

大括号之谜:C++的列表初始化语法解析