2013-05-02 3 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 errorvため

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

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 
} 

私の質問はです。どのように初期化リストを使ってメンバー配列を初期化できますか?あなたのクラスがaggregateある場合(つまり、どのように私は?最初のコードの仕事をしたり、それは不可能ですか?

+0

集約の場合、ctorは必要ありません。 'initializer_list'のサイズは可変であることに注意してください。 'initializer-list'で初期化することと、_list-initialization_(これは言語構成であり、initializer-listを使ってctorを呼び出すことにつながる可能性があります)との違いもあります。 – dyp

+0

実際にはできませんが、代わりに 'std :: array'を使用できますか? – juanchopanza

+0

彼はstd :: arrayを使うことができましたが、標準ライブラリではなく、言語に関する質問としてこれを読んでいます。そして、誰かを正当に尊重して、誰かに標準ライブラリを読むように言うことは、シェイクスピアを読んで幼児に英語を学ばせるようなものです。だからstd :: arrayは非常に良い答えではありません。 –

答えて

9

することは、あなたは

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

Vector<3> v = {1.0f, 2.0f, 3.0f}; 
あなたの構文を使用することができます

注:これはbrace-elisionのために可能です。v = {{1,2,3}};の必要はありません。この警告は、エラーが発生しやすい明瞭な構文が二重括弧(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の容量よりも大きい場合はどうなりますか? –

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'を推奨しています。それは初期化のためのより良い構文を可能にします。 –

0

アレイ非スタティックメンバーを初期化するには、集約構文を使用します。つまり、N要素で直接補完リストを埋めてください。ここで、Nは配列の要素の数です。要素タイプがDefault-Constructibleの場合は、Nより小さい値を使用できます。不足している要素は値で初期化されます。

std::initializer_listから配列への変換はありません。配列参照(値ではない)に変換できるソースタイプを使用していたとしても、配列が割り当て可能ではないため、メンバー初期化子で変換を悪用することはできません。このような場合は、コンストラクタの本体内にstd::copyのようなものを使用する必要があります。

多次元配列の場合、配列は割り当て可能ではないため、サブ配列を表すためにブレースリストのみを使用します。ブレース溶出のオプションもあります。 std::remove_all_extents<TheArrayType>::type項目のフラットリストを使用し、コンパイラはmake-doを行います。 (非配列型の内部型が組み込みの文字型の場合、多次元配列の中で最も内側にある次のものとして、引用符付きの文字列を使用することがあります。)

関連する問題