2017-01-02 5 views
0

コードスニペットを汎用的にしようとしていますが、コードに使用されている手法がどのように機能しているかを完全には理解していないため、このC++コードの汎用性を確認してください

私は別の質問からコードを得た:ここ

C++17 construct array in stack using choosen constructor (same constructor parameter values for each array entry)は、この記事の最初の応答に基づいてコードですが、それはいくつかの理由が88を超える大きさで作業していないためである。 http://ideone.com/WDlNwd

#include <iostream> 
#include <utility> 

struct A1 { 
    A1() { 
     printf("A1() called\n"); 
    } 

    A1(std::size_t i) { 
     printf("A1(%d) called\n", i); 
    } 

    A1(std::size_t i, std::size_t j) { 
     printf("A1(%d, %d) called\n", i, j); 
    } 
}; 

struct A2 { 
    A2(std::size_t i, std::size_t j, double k) { 
     printf("A2(%d, %d, %lf) called\n", i, j, k); 
    } 
}; 

template <class T, size_t Size> 
class B { 
    template<typename Arg1, typename ...Args, size_t... Is> 
    B(std::index_sequence<Is...>, const Arg1 &arg1, const Args &...args) : 
    tab{ {(void(Is), arg1), args... }... } 
    {} 

    public: 

    T tab[Size]; 

    B() = default; 

    template<typename ...Args> 
    B(const Args &...args) 
     : B(std::make_index_sequence<Size>(), args...) {} 
}; 

int main() { 
    static constexpr size_t Size = 100; 
    B<A1, Size> b1(11, 17); 
    B<A1, Size> b1a(11); 
    B<A1, Size> b1b; 
    B<A2, Size> b2(11, 17, 1.2); 
    return 0; 
} 

ありがとう

+2

引数を複数回 'std :: forward'しないでください。それがいつ動くかはわかりません。それを防ぐには、参照を転送するのではなく、 'const&'として引数を取るべきです。 –

+0

std :: vector :: emplace_back()のSTL実装は、私と全く同じ構造体を使用しています。私は、STLコードで見つかったパターンを悪意のある行為を避ける目的で使用しました。それは、移動やコピーを生成することができますか? – infiniteLoop

+0

@mikeDundee 'emplace_back'はパラメータを一度しか使用していないと思いますか? NicolBolasのコメントについての私の理解は、最初の使用で消費される可能性があるため、 'std :: forward'が与えられたr値参照を1回だけ転送することができ、次に参照がゼロのオブジェクトを指し示すかもしれないということです... –

答えて

1

答えは実質的にthe answer you got on the last oneと同じです。唯一の違いは、ゼロパラメータを渡す特別なケースが必要なことです。 index_sequenceパラメータの順序を調整します。

struct B { 
    A tab[100]; 

    //Note: feel free to use SFINAE to make this go away 
    //if `A` is not default-constructible. 
    B() = default; 

    template<typename ...Args> 
    B(const Args &...args) 
     : B(std::make_index_sequence<100>(), args...) {} 

private: 

    template<typename Arg1, typename ...Args, size_t... Is> 
    B(std::index_sequence<Is...>, const Arg1 &arg1, const Args &...args) 
     : tab{ {(void(Is), arg1), args... }... } {} 
}; 
+0

ありがとうございますが、パラメータの型がstd :: size_tの場合、これは動作しません:http://ideone.com/WDlNwd – infiniteLoop

+0

@mikeDundee:どのようなパラメータパックを分けていますか?問題は、 'int'引数から' size_t'引数への変換が狭くなり、リスト初期化が禁止されることです。私はリスト初期化の愚かさを修正することはできません。したがって、あなたは2つの選択肢があります:あなたはあなたの 'B'を作成するときに引数をキャストすることができます(http://ideone.com/5Tpqgx)。あるいは、リスト構文の代わりにコンストラクタ構文で 'A'型を構築することもできます。つまり、集約では機能しません。 –

+0

あなたのソリューションが87または88以下の配列サイズで動作しているが、これより上ではないことがわかりません。これは奇妙です。私はリストの初期化がどのように拡大しているのか理解できません。インデックスシーケンスは可変パラメータですが、そうではありません。 – infiniteLoop

関連する問題