2016-04-03 6 views
1

私は、リスト変数を持っていて、変数のサイズはconstです。これは、リストのサイズが実行ごとに異なりますが、個々の実行では変更できないという要件が強制されるため、私にとって役に立ちます。1つの要素で塗りつぶすことによってstd :: arrayを構築します

これらのリストのコレクションを作成したいと思います。コレクション内のリストの数はテンプレート変数ですので、std::arrayを使用したいと思います。つまり、配列のサイズがテンプレートのパラメータであり、それぞれのサイズリストは

残念ながら、構築時に指定したconst次のとおりです。

  • constのサイズのリストがあるデフォルトコンストラクタません(そのサイズを指定する必要があります!)ので、私はの各要素に、コンストラクタの引数を指定する必要がありますリスト。私は、配列を作成し、要素を設定することはできません
  • 私のリストのサイズは、テンプレート変数があるので、私は標準の初期化子リストを使用することはできません - 必要な数の要素が

を変える私がいることを認識あり選択肢は以下のとおりです。

  • それが自然という条件を強制しないので、ベクトルの大きさは、私のテンプレートパラメータと同じであるが、これは洗練思えるまで、私は一つstd::vectorだけpush_back要素1を使用することができます結果のベクトルのサイズは、完全に取り込まれた後は変更しないでください。
  • 私はインデックスの順序を反転し、std::arraysのconstサイズのリストを持つことができます。しかし、これは他のコードとうまく適合しません。配列から個々のconstサイズのリストをクライアントコードに渡すことができるようにしたい
  • constサイズのリストクラスのデフォルトコンストラクタを作成し、配列を作成してからnewを使用して配列要素を置き換えます一つずつ。それは(それが誤って別の場所に呼ばれていますどのような場合にはconstのサイズのリストのデフォルトコンストラクタが?何をするのでしょうか?私の後継者は、私が何をやったかは考えていないときに何が起こる?)

いくつかの悪い副作用を持つことができるようにこれは思えますこれらのどれもが完全に理想的ではないので、私がいたならば、それは素晴らしいことだろうと思っている配列コンストラクタの引数として取る(またはヘルパー機能)、:

  1. Tの配列の要素数
  2. 単一のTオブジェクト

...そしてstd::array<T>を返します。それぞれTは引数2からコピー構築されています。

このようなことはありますか?

+0

"各リストのサイズは、構築時に指定されたconstです" - 私はあなたも*コンパイル時*を意味することを願っています。さもなければ、get-goから 'std :: array 'を使う考えを投げることができます。 – WhozCraig

+0

リストのサイズはコンパイル時定数ではありません。 – user1476176

答えて

2

テンプレートマジック。 std::arrayが集合型であるとして、集計の初期化を使用して初期化することができます。

std::array<T, 5> arr = { one, two, three, four, five }; 

アイデアは、oneです...、fiveが使用して、タイプT(あなたのケースでは、リスト)の構築されたオブジェクトの5つのコピーですパラメータとしてのユーザ入力。だから、遊ぶことができます。笑ったり、これを読んだ後泣かないでください:

アイデアは5回型Tの目的の一つを取り、それを複製することです:

{ T(param), .... }; // Five repetitions. 

だから、すでに初期化配列を返す関数を作成することができます:

std::array<A, 5> arr = create_array_by_copy<5>(A(10)); 

この関数は、その一時オブジェクトのarray<A, 5>5とのコピーを返します。そのために

、我々は(sとしてパラメータ化)5の長さをパラメータパックを作成する補助structを使用します。

template<std::size_t s, class... voids_t> 
struct sized_pack : public sized_pack<s - 1, voids_t..., void> 
{}; 

template<class... voids_t> 
struct sized_pack<0, voids_t...> 
{}; 

これは単にあるvoids_tというパラメータパックを、作成します。 svoidのリストそして今、トリックの中心:

template<std::size_t s, class T, class... pack_t> 
std::array<T, s> 
create_array_by_copy_helper(sized_pack<0, pack_t...> const&, 
          T const& o) 
{ return { (pack_t(), o)... }; } 

template<std::size_t s, class T> 
std::array<T, s> create_array_by_copy(T const& o) 
{ 
    return create_array_by_copy_helper<s>(sized_pack<s>(), o); 
} 

これは複雑です。私は知っている... sized_pack<s>のオブジェクトをヘルパー関数に渡したので、その一時オブジェクトはsized_packの階層をインスタンス化し、最後の基本クラスはsized_pack<0, void, void, void, void, void>のオブジェクトになります。

関数適用は、(最後のベースクラス、最初0に注意)size_pack<0, pack_t...>への参照としてそのオブジェクトを受信することになるので、pack_t 5つのvoid Sの私たちのリストであろう。

は最後に、我々は持っている:

ある
(pack_t(), o) 

だけでコンマ演算子は、そう、それはoを返します。考え方は、...を式に適用すると、pack_t(パラメータパック)が挿入されているため、コンマ区切りの式に置き換えられます。ここで、各pack_tの外観は、パラメータので、同じ順序でパック:

{ (pack_t(), o)... } 

がに変換されます。

{ (void(), o), (void(), o), (void(), o), (void(), o), (void(), o) } 

初期化リスト!!最後に、各要素は、voidの式の後に昏睡演算子が続き、各ペアの2番目の要素だけがコンマ演算子によって返されます。したがって、評価式は次のようになります。

return { o, o, o, o, o }; // With its corresponding calls to `forward`. 

希望する初期化リスト!!

Coliru例:

http://coliru.stacked-crooked.com/a/d6c4ab6c9b203130

あなただけのリストクラスでタイプTを置き換えする必要があります。

+0

なぜあなたは 'std :: make_integer_sequence'を再発明していますか? –

+0

さて、私はそれが存在するかどうかはわかりませんでした。とにかく、C++ 14の機能であり、g ++ 4.8.4のように今日でもまだ使われているコンパイラのバージョンでは、C++ 14を完全にサポートしていません。 –

+1

クール!私はこの回答を受け入れていますが、他の人が私の質問の以前の化身に与えた回答を見ることに興味があるかもしれません:http://stackoverflow.com/questions/18497122/how-to-initialize-stdarrayt-n-エレガントな場合は、デフォルトで構成できない場合は – user1476176

0

std::array<T, N>は、タイプTの要素の長さがNの配列を表すテンプレートクラスです。リストの配列を作成したいのであれば、std::array<std::list<T>>, N>Nとすると、コンパイル時にはとなります。 const std::size_t Nで十分ではなく、constexprでなければなりません。

だから、できません。ただし、std::vectorを使用することができます。

あなたの努力のコードを投稿すれば、より良いものを見つけることができます。

+0

ありがとう!私はおそらくconstのサイズのリストへのポインタのstd ::配列を格納し、new()を使って適切なサイズのリストを作成するのが最も簡単かもしれないと考えています。私はnew-ingとdeleteについて心配する必要がありますが、それは後でできることを保証します。 – user1476176

+0

@ user1476176スマートポインタを使うと、メモリ割り当て/解放自体を処理します。 – Zereges

関連する問題