一般化されたミキシン
-
27-10-2019 - |
質問
私は、ミキシンをバリアードテンプレートパラメーターとして受け入れることができるクラスがあるコードを書いていました。ただし、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? */
解決
私は問題を理解しているかどうかよくわかりませんので、右足で始めることができるように、それを言い換えさせてください。
典型的なCRTPユースケースで、派生タイプを基本クラスにスレッドする必要がありますが、同時に他のテンプレートパラメーターをさまざまなベースクラスに渡す必要があります。
つまり、典型的な基本クラスは次のとおりです。
template <typename Derived, typename X, typename Y>
struct SomeBase {
};
そして、あなたはあなたが制御できるようにあなたのタイプを作成する必要があります X
と Y
同時に完全に合格します Derived
クラス。
私はそれを使うと思います apply
の引数リストに記載されているアダプターから、その場でベースクラスを生成するためのトリック Derived
クラス。
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;
};
次に、次のタイプを作成します。
typedef MyFoo< SomeBaseFactory<int, float> > SuperFoo;
どこ Foo
と定義されている:
template <typename... Args>
struct Foo: apply<Args, Foo<Args...>>::type... {
};
そして、私がテンプレートを深く駆り立ててからしばらく経ちました。 私はそれが機能したことを確認しました.
もちろん、 Factory
それ自体は実際には特定のタイプに固有のものではないため、実験したラッパーアプローチを再利用できます。
template <template <typename...> class M, typename... Args>
struct Factory {
template <typename Derived>
struct apply { typedef M<Derived, Args...> type; };
};
はい、 それも機能します.
他のヒント
質問を正しく理解している場合は、各ミックスインを単一のテンプレートパラメーターに削減するテンプレートエイリアスを作成する必要があります。
template <typename Derived>
using BarIntFloat = Bar<Derived, Int, Float>;
template <typename Derived>
using BazQux = Baz<Derived, Qux>;
typedef Foo<BarIntFloat, BazQux> MyFoo;
これが私が思いついた解決策です。これを行うためのよりエレガントな方法があるかもしれませんが、私は考えられませんでした。 1つの注意点は、使用されるすべてのミキシンが最初にネストされる必要があることです wrapper
構造体、それぞれの議論。
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;
}
@void-pointer
これは、ヴァリヤディックテンプレートの基本的な省略です。ユーザーはtからi番目のタイプを取得できません...または値からi番目の値を取得できません...
ここは リンク Andrei Alexandrescuによる2012年のネイティブ講義から:
template <typename... Ts>
void fun(const Ts&... vs) {}
•TSはタイプではありません。 VSは価値ではありません!
typedef Ts MyList; // error!
Ts var; // error!
auto copy = vs; // error!
したがって、TS/VSは何らかのタプルでなければなりません。