2013-05-02 206 views
9

我有一个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

I tried using parentheses instead of bracesv但给了错误:

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

我对试图做到这一点的主要动机是为了避免下面警告叮当:

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

所以我的问题是:我怎样才能初始化一个成员数组与初始化列表? (即我怎样才能使第一个代码工作?或者是不可能的?

+0

对于一个聚合,你甚至不需要ctor。请注意'initializer_list'的大小是可变的。 initializer-list初始化和_list-initialization_(这是一种语言结构,并可能导致使用初始化器列表调用ctor)之间也有区别。 – dyp 2013-05-02 14:54:29

+0

你真的不能这样做,但是你可以使用'std :: array'吗? – juanchopanza 2013-05-02 14:54:52

+0

他可以使用std :: array,但是我把它看作是关于语言的问题,而不是标准库。而且,在适当尊重任何人的情况下,告诉某人去读标准图书馆就像告诉幼儿通过阅读莎士比亚来学习英语一样。所以std :: array不是一个很好的答案。 – 2016-03-02 00:32:35

回答

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

尝试使用std::copy

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

如果列表大于v的容量,该怎么办? – 2016-03-02 00:25:52

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}}; 
} 
+0

+1推荐'std :: array'。它允许更好的初始化语法。 – 2013-05-02 15:05:25

0

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

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

注意多维数组,因为数组不是可指定的,所以只能使用支撑列表来表示子数组。也有选择大括号的方法;使用一个std::remove_all_extents<TheArrayType>::type项目的扁平列表并且编译器将make-do。 (当内部非数组类型是内置字符类型时,有时可以使用带引号的字符串作为多维数组的下一个内部初始化程序。)

相关问题