2016-04-14 3 views
2

Faheem Mithaというユーザーの下のコードは、このユーザーのJohannes Schaub - litbの回答をSOに基づいています。このコードは、tupleのパラメータパックへの変換である私が求めていることを完全に行いますが、私はこのコードを十分に理解していないので、私のようなテンプレートのメタプログラミングを助けるかもしれない新しい議論を作成すると考えました。だから、重複投稿をご容赦ください。今すぐコードタプルからパラメータパック

#include <tuple> 
#include <iostream> 
using std::cout; 
using std::endl; 

template<int ...> struct seq {}; 

template<int N, int ...S> struct gens : gens<N - 1, N - 1, S...> { }; 

template<int ...S> struct gens<0, S...>{ typedef seq<S...> type; }; 

double foo(int x, float y, double z) 
{ 
    return x + y + z; 
} 

template <typename ...Args> 
struct save_it_for_later 
{ 
    std::tuple<Args...> params; 
    double(*func)(Args...); 

    double delayed_dispatch() 
    { 
     return callFunc(typename gens<sizeof...(Args)>::type()); // Item #1 
    } 

    template<int ...S> 
    double callFunc(seq<S...>) 
    { 
     return func(std::get<S>(params) ...); 
    } 
}; 

int main(void) 
{ 
    std::tuple<int, float, double> t = std::make_tuple(1, (float)1.2, 5); 
    save_it_for_later<int, float, double> saved = { t, foo }; 
    cout << saved.delayed_dispatch() << endl; 
    return 0; 
} 

上に移動

は、私は完全に上記のアイテム#1によって混乱しています:

  • typenameは、その行にどのような目的を果たしていますか?
  • gens<sizeof...(Args)>::type()gens<3>::type()に拡張されますが、それはtemplate<int N, int ...S> struct gens : gens<N - 1, N - 1, S...> { };でもtemplate<int ...S> struct gens<0, S...>でも一致しません。私は明らかにその点を見逃しています。誰かがここで何が起きているのかを説明できると嬉しいです。

私はcallFuncは、このフォームcallFunc(seq<0,1,2>)で呼び出されると、この方法自体のreturn文がreturn func(std::get<0>(params), std::get<1>(params), std::get<2>(params)に展開し、これは、このスキームの仕事を作るものですが、私はこのseq<0,1,2>型が生成される方法をトレーニングできないことを理解してください。

注:std::index_sequence_forを使用することはできません。私のコンパイラはC++ 14の機能をサポートしていません。

PS:このテクニックをテンプレートメタプログラミングと分類できますか?

+1

1) 'gens :: type'はメンバ関数ではなく、型であることをコンパイラに知らせるためです。 2)パラメーターパックを空にすることができます。 –

+1

'gens <3>'は 'template struct gens'と一致しません。' N == 3'と 'S'は空のパックです。 –

+1

基本的に 'seq'は' 'std :: index_sequence'(http://en.cppreference.com/w/cpp/utility/integer_sequence)で、' gens'は 'std :: make_index_sequence'です –

答えて

7

のは、ここに何が起こるか見てみましょう:

template<int N, int ...S> struct gens : gens<N - 1, N - 1, S...> { }; 

template<int ...S> struct gens<0, S...>{ typedef seq<S...> type; }; 

最初のものは、一般的なテンプレートで、二番目は、最初のテンプレートパラメータが今0

ときに適用される専門で、取ります紙と鉛筆の部分を書き、その内容を書き留めてください。

gens<3> 

は、上記のテンプレートで定義されています。あなたの答えが:

struct gens<3> : public gens<2, 2> 

でした。これは、Nが "3"で...Sが空の場合に最初のテンプレートが展開される方法です。 gens<N - 1, N - 1, S...>は、gens<2, 2>となります。

さあ、行き続ける、とgens<2, 2>が定義されます方法を見てみましょう:

ここ
struct gens<2, 2> : public gens<1, 1, 2> 

は、テンプレート展開で、Nは2で、...Sは "2" です。さて、次のステップを取る、とgens<1, 1, 2>が定義されている方法を見てみましょう:

struct gens<1, 1, 2> : public gens<0, 0, 1, 2> 

[OK]を、今どのようにgens<0, 0, 1, 2>が定義されますでしょうか?今では専門によって定義することができます

だから、
template<int ...S> struct gens<0, S...>{ typedef seq<S...> type; }; 

、ここstruct gens<0, 0, 1, 2>で何が起こりますか?まあ、専門では、「Sは...」「2、1、0」となり、これは話すの方法で、次のようになります。これらのすべては公に継承覚えておいて、今

struct gens<0, 0, 1, 2> { 

    typedef seq<0, 1, 2> type; 

} 

お互いに、「象スタイル」、そう:

gens<3>::type 

struct seq<0, 1, 2> 

のtypedef宣言されて終わるそして、これは、パラメータ・パックにタプルを変換するために、次のコードによって、使用されています別のテンプレートを使用して:

double delayed_dispatch() 
{ 
    return callFunc(typename gens<sizeof...(Args)>::type()); // Item #1 
} 

...Argsはタプルのパラメータです。したがって、タプルに3つの要素がある場合、sizeof(...Args)は3であり、上記で説明したように、gens<sizeof...(Args)>::type()gens<3>::type()、a.k.a. seq<0, 1, 2>()になります。

だから、今:

std::get<0>(params), std::get<1>(params), std::get<2>(params), 

std::get<S>(params)... 

はに拡大しますパラメータパックになるように

template<int ...S> 
double callFunc(seq<S...>) 
{ 
    return func(std::get<S>(params) ...); 
} 

S...部分は、 "0、1、2" となり

これがタプルがパラメータパックになる方法です。

+0

非常に明確な説明をありがとう。 – DigitalEye

関連する問題