2012-02-19 19 views
3

私は、ミックスインをバリデーションテンプレートパラメータとして受け入れることができるクラスをいくつか作成しました。しかし、CRTPイディオムを通して基本クラスにアクセスできるようにするためには、ミックスインも必要です。ここでは、非常に私がやりたいことができない、最小限の例です:一般化されたミックスイン

template <template <class> class... Mixins> 
class Foo : Mixins<Foo<Mixins...>>... {}; 

はしかし、私はFooに渡すかもしれないミックスインは、一般的には、いくつかのテンプレートパラメータを持つことになりますので、のように:どのように

template <class Derived, class Type1, class Type2> 
class Bar 
{ 
    Derived& operator()() 
    { 
     return static_cast<Derived&>(*this); 
    } 
}; 

Fooを変更して、いくつかの基本クラスから継承させることができます。ここで、各基本クラスで受け入れられるテンプレートパラメータを制御しますか? Fooにテンプレートテンプレートパラメータのリストとそれに渡す引数のリストを渡すと、各テンプレートテンプレートパラメータとその引数をどのように関連付けることができるのかわかりません。これまでのところ、私はこのようなことを考えましたが、どのように進むのか分かりません。

template <template <class...> class T, 
    template <class...> class... Ts> 
class Foo : /* How do I retrieve the arguments? */ 

答えて

4

私はこの問題を理解しているとは思っていませんので、右足で始めることができるように言い換えてください。

一般的なCRTPユースケースでは、派生型を基本クラスにスレッド化する必要があります。同時に、他のテンプレートパラメータをさまざまな基本クラスに渡す必要があります。ある

は、典型的な基底クラスは次のようになります。

template <typename Derived, typename X, typename Y> 
struct SomeBase { 
}; 

そして、あなたは、あなたがXYを制御すると同時に、完全なDerivedクラスを渡すことができるようにあなたのタイプを作成する必要がありますたいです。


私はDerivedクラスの引数リストで提供アダプタから、その場で基本クラスを生成するapplyトリックを使うと思います。

template <typename Derived, typename X, typename Y> 
struct SomeBase {}; 

template <typename X, typename Y> 
struct SomeBaseFactory { 
    template <typename Derived> 
    struct apply { typedef SomeBase<Derived, X, Y> type; }; 
}; 

// Generic application 
template <typename Fac, typename Derived> 
struct apply { 
    typedef typename Fac::template apply<Derived>::type type; 
}; 

次に、あなたがしたようなタイプを作成します。

Fooは次のように定義されて
typedef MyFoo< SomeBaseFactory<int, float> > SuperFoo; 

template <typename... Args> 
struct Foo: apply<Args, Foo<Args...>>::type... { 
}; 

そして、私はテンプレートでとても深くtrudgedので、それがしばらくしているというだけの理由、I checked it worked。もちろん


Factory自体は本当に特定のタイプに固有ではありませんので、我々はあなたが実験していたラッパーのアプローチを再利用することができます

template <template <typename...> class M, typename... Args> 
struct Factory { 
    template <typename Derived> 
    struct apply { typedef M<Derived, Args...> type; }; 
}; 

そして、はい、it works too

+0

これは明らかに最も洗練されたソリューションです。申し訳ありませんが、私の質問が少しあいまいでした。 –

+0

@ void-pointer:必ずしもあいまいであるとは言えませんが、いくつかの層があり、私が解決しようとしていた問題をはっきりと表現することができたので、間違った方向に向いていれば修正できます。 –

2

質問が正しく分かったら、各ミックスインを1つのテンプレートパラメータに減らすテンプレートエイリアスを作成する必要があります。

template <typename Derived> 
using BarIntFloat = Bar<Derived, Int, Float>; 

template <typename Derived> 
using BazQux = Baz<Derived, Qux>; 

typedef Foo<BarIntFloat, BazQux> MyFoo; 
+0

私はテンプレートのエイリアスを使ってこれを達成することを考えていませんでした。答えに感謝します。 1つの注意点は、より多くのミックスインを使用する必要があるため、状況が不便になることです。私は、テンプレートエイリアスなしで動作するようだが、おそらくそれを行うより良い方法がありますハックを思い付いた? –

+0

私はCRTPを取得するためにテンプレートエイリアスが必要だと思っていますが、ラッパーにラップアラートして、素敵で使いやすいものを得るかもしれません。申し訳ありませんが、コンパイル時にエイリアスをサポートしていないため、テストできません。 –

+0

ええ、私の解決策はテンプレートエイリアスをサポートしていないコンパイラを持っていなくても、テンプレートエイリアスなしでは期待どおりに動作するようです。 g ++ 4.7はありますが、公式リリースまでお待ちしています。 –

0

これは私が思いついた解決策です。これを行うためのよりエレガントな方法があるかもしれませんが、私は考えることができませんでした。 1つの注意点は、使用されるすべてのミックスインが、最初に構造体のそれぞれの引数とともに入れ子にされる必要があることです。

ボイドポインタ@
template <template <class...> class Mixin, class... Args> 
struct wrapper 
{ 
     typedef Mixin<Args...> type; 
}; 

template <class... Args> 
struct test 
{ 

}; 

template <class Arg, class... Args> 
struct test<Arg, Args...> : Arg::type, test<Args...> 
{ 

}; 

template <class T> 
class mixin1 {}; 

template <class T1, class T2> 
class mixin2 {}; 

template <class T1, class T2, class T3> 
class mixin3 {}; 

int main() 
{ 
     test<wrapper<mixin1, int>, wrapper<mixin2, int, float>> foo; 
     return 0; 
} 
0

これは、可変長引数テンプレートの基本的な省略です。ユーザーはここでTからi番目の型を取得...または値からi番目の値を取得...

することはできませんアンドレイアレキによってネイティブ2012講義に行くからa linkです:Tsはない•

template <typename... Ts> 
void fun(const Ts&... vs) {} 

タイプ。 vsは値ではありません!

typedef Ts MyList; // error! 
Ts var; // error! 
auto copy = vs; // error! 

したがって、Ts/vsは何らかのタプルである必要があります。

+0

私はあなたが多少質問を逃したと思いますが、私はインデックスによるアクセスが期待されたというヒントは見ませんでした。 –

+0

"ユーザーはT ...からi番目の型を取得できません" - 簡単に、 'T ...'を 'std :: tuple'に展開し、' std :: tuple_element'を使用してください。同じvorの値...。 – Xeo

関連する問題