2016-12-19 6 views
2

パック(。私はこの質問に名前を付けると私は似た何かを見つけることができませんでしたかわからなかった申し訳ありませんが、これは重複している場合)C++:パラメータを使用して、変数の型パラメータを持つテンプレートクラスの継承が

私は継承したい場合いくつかの基本テンプレートクラスから、私はこのような方法行うことができます。

template<typename A=int, typename B=char> class C {}; 
template<typename... Args> class D : public C<Args...> {}; //it works! 

を私はプロジェクトに変更することができますこの方法は、テンプレートクラスCにパラメータを渡すと、私はクラスD.グレートのすべての使用法を変更する必要はありません。しかし、パラメータとして型だけでなく値も使用するテンプレートクラスがあればどうでしょうか?例:

template<int dim=3, typename float_t=double> class GeometricObject{}; 
template<typename... Args> class Point : public GeometricObject<Args...>{}; //it doesnt work 

もちろん、最初に整数型の最後のテンプレートを定義できます。しかし、これは方法ではありません.GeometricObjectから継承した100種類のクラスがある場合、デフォルトのdimの値を2に変更すると、すべての単一クラス定義を変更する必要があります。

また、#define#elseなどのプリプロセッサコマンドを使用しない方法があることを願っています。実際にはテンプレートもプリプロセッサコマンドであることはわかっていますが...ここでは現代的にしようとします)

+0

は型パラメータから分離され、あなたの価値のパラメータであり、すなわち値のパラメータは、常にこの 'テンプレート '? –

+0

それは可能性があります。私は一般的な答えがわからない場合は、特定の答えも良いです:) – Ch3shire

+0

あなたは特殊なテンプレートを直接渡して、適切なtypedefでパラメータパックにアクセスできませんか? – Rerito

答えて

4

テンプレートパラメータパックでタイプパラメータと非タイプパラメータを混在させることはできません。しかし、あなたのPointと他の派生クラスは、パラメータパックの引数に別々にアクセスする必要はありません。このような場合には、基本クラスを渡すために、より多くの意味的に正しい簡単だ、など:GeometricObject<...>はtypedefさすることができ

もちろん
Point<> a{}; // the same as Point<GeometricObject<>> a{}; 
Point<GeometricObject<4>> b{}; 
Point<GeometricObject<2, float>> c{}; 

Pointをインスタンス化

template<int dim=3, typename float_t=double> class GeometricObject{}; 
template<class GeometricObject=GeometricObject<>> class Point : public GeometricObject{}; 

はその後のようになります。何か短い。また、代わりに別途、各幾何学的オブジェクトにパラメータを提供する名前空間のように見えるようにすることができる。

template<int dim = 3, typename float_t = double> 
struct GeometricObjects { 
    using Base = GeometricObject<dim, float_t>; 
    using Point = ::Point<Base>; 
    // ... 
}; 

using TwoDim = GeometricObjects<2>; 
TwoDim::Point a{}; 
+0

これはどんなウィザードですか?私は 'using'ステートメントはC#のドメインだと思っていました。レスポンスありがとう! – Ch3shire

+1

'Using TwoDim = GeometricObjects <2>'は 'typedef GeometricObjects TwoDim'と同じですが、ちょうど" modern "です:-) –

+1

どの部分がウィザードのように見えますか?私は詳しく説明します。 –

2

私はあなたが複数のテンプレートクラスを持って、あなたはあなたのPointオブジェクトはそれらすべてを継承することができるようにしたいとします。

の代わりにやって:

template <typename ... Args> 
class Point : public GeometricObject<Args...>{}; 

を私が代わりに行います:

template <typename T> 
class Point : public T {}; 

を今はちょうど彼らが必要な場合には種類のテンプレートパラメータにアクセスするには、適切な特性を定義する必要があります。これらのタイプは、たとえばstd::tupleに組み込む必要があります。

この特性を満たす負担は、GeometricObjectクラスにあります。たとえば、あなたの定義と、私たちは持っているでしょう:

template <typename T> 
struct type_parameters; 

template <int N, typename Float> 
struct type_parameters<GeometricObject<N, Float> { 
    typedef std::tuple<Float> types; 
}; 

メインシナリオ:Pointの方法は、(GeometricObjectの方法にそれらを転送するために)GeometricObjectの種類のテンプレートパラメータを必要とします。これを実現するには、tupleを渡す必要があります。このメソッドは内部メソッドを呼び出すために展開されます。これを行うために、私はSTL for C++ 14に追加された機能を利用します。あなたはまだそれらを自分で書き直すことができましたが、私はこの質問のための手間を省いてくれました...

template <typename T> 
class Point : public T { 
    template <typename Method, typename ... Args, std::size_t ... Is> 
    auto call_unfold(Method method, std::tuple<Args...> const& tuple, std::integer_sequence<std::size_t, Is...>) { 
     return (this->*method)(std::get<Is>(tuple)...); 
    } 
    template <typename Method, typename Tuple> 
    auto call_unfold(Method method, Tuple const& tuple) { 
     return call_unfold(method, tuple, std::make_index_sequence<std::tuple_size<Tuple>::value>()); 
    } 
public: 
    typedef typename type_parameters<T>::types types; 
    void some_method(types const& args) { 
     return call_unfold(&T::some_method, args); 
    } 
}; 

この例は非常に意味がありますが、同じ技術は、基本クラスのコンストラクタを呼び出す必要がPointのコンストラクタで有用である可能性があります。

それがどのように動作するかを示すのライブデモが[OK]をColiru

+0

ありがとう回答。私はオプションがないように見える、私はテンプレートを混乱させたい場合は、より複雑なコードを作成する必要があります。ありがとう! :) – Ch3shire

0

で提供されていますので、私は、私はタプルへの変数の型テンプレートパラメータを含める必要がありますどのようにそれを考え出しました。基本的には、それらを新しいパラメータにカプセル化する必要があります。この例では、完全にうまく機能し、私の問題を解決します:

#include <type_traits> 

template<int n = 2> struct Dim { 
    const int dim = n; 
}; 

template<typename T> class SillyBaseClass { 
public: 
    typedef typename T dim; 
}; 

template<typename... Args> class SillyDerivedClass : public SillyBaseClass<Args...>{ 
public: 
    typedef typename SillyBaseClass::dim dim; 
    SillyDerivedClass() { 
     static_assert(std::is_same<dim,Dim<2>>::value, 
      "Number of dimensions must be equal to 2"); 
    } 
}; 

int main() { 

    SillyDerivedClass<Dim<2>> Class2d; //this works 
    SillyDerivedClass<Dim<3>> Class3d; //this returns expected error 

} 
関連する問題