使用初始化列表初始化成员数组的正确方法是什么?

时间:2013-05-02 14:48:39

标签: c++ c++11

我有一个struct,它包含一个数组,我想将一个初始化列表传递给struct的构造函数,以便转发给数组。为了说明,我试过了:

#include <initializer_list>

struct Vector
{
    float v[3];

    Vector(std::initializer_list<float> values) : v{values} {}
};

int main()
{
    Vector v = {1, 2, 3};
}

Which resulted in the error

  

error: cannot convert ‘std::initializer_list<float>’ to ‘float’ in initialization

对于v

I tried using parentheses instead of braces但是出现了错误:

  

error: incompatible types in assignment of ‘std::initializer_list<float>’ to ‘float [3]’

尝试这样做的主要动机是避免clang生成的以下警告:

template <int N>
struct Vector
{
    float v[N];
};

template <>
struct Vector<2>
{
    float x, y;
};

int main()
{
    Vector<2> v2 = {1.0f, 2.0f};         // Yay, works
    Vector<3> v3 = {1.0f, 2.0f, 3.0f};   // Results in warning in clang++
    Vector<3> u3 = {{1.0f, 2.0f, 3.0f}}; // Must use two braces to avoid warning
    // If I could make Vector<N> take an initializer list in its constructor, I
    // could forward that on to the member array and avoid using the double braces
}
  

warning: suggest braces around initialization of subobject

所以我的问题是:如何使用初始化列表初始化成员数组? (即如何使第一个代码生效?或者它不可能?

4 个答案:

答案 0 :(得分:12)

纯C样式数组不可分配。如果切换到使用std::array,则初始化变得微不足道。

#include <array>

struct Vector
{
    std::array<float, 3> v;

    Vector(std::array<float, 3> const& values) 
    : v(values)
    {}
};

int main()
{
    Vector v{{1, 2, 3}};
}

答案 1 :(得分:9)

如果您的课程是aggregate,则可以使用语法

template < std::size_t len >
struct Vector
{
    float elems[len];
};

Vector<3> v = {1.0f, 2.0f, 3.0f};

注意:由于支撑省略,这是可能的。不需要v = {{1,2,3}};虽然这也是可能的。 Clang发出此警告是因为更加清晰且不易出错的语法是双括号(一个用于初始化v,另一个用于初始化子聚合elems)。

如果您的类不是聚合,则可以使用可变参数模板:

#include <array>
#include <cstddef>

template < std::size_t len >
struct Vector
{
    std::array < float, len > m;  // also works with raw array `float m[len];`

    template < typename... TT >
    Vector(TT... pp) : m{{pp...}}
    {}

    // better, using perfect forwarding:
    // template < typename... TT >
    // Vector(TT&&... pp) : m{{std::forward<TT>(pp)...}}
    // {}
};

Vector<3> a = {1.0f, 2.0f, 3.0f};

答案 2 :(得分:2)

尝试使用std::copy

Vector(std::initializer_list<float> values) 
{
    std::copy(values.begin(), values.end(), v);
}

答案 3 :(得分:0)

要初始化数组非静态成员,请使用聚合语法。也就是说,直接用N元素填充括号列表,其中 N 是数组中元素的数量。如果元素类型是Default-Constructible,则可以使用少于 N ;缺少的元素将被初始化。

没有从std::initializer_list到数组的转换。即使您使用的源类型可以转换为数组引用(从不是值),也无法在成员初始化程序中利用转换,因为数组不是可分配的。在这些情况下,您必须在构造函数体内使用std::copy之类的内容。

注意多维数组,因为数组不是可分配的,所以只使用括号列表来表示子数组。还有选择括号省略;使用std::remove_all_extents<TheArrayType>::type项的平面列表,编译器将生成。 (当内部非数组类型是内置字符类型时,有时可以使用带引号的字符串作为多维数组的下一个最内层初始值设定项。)