2016-09-25 5 views
1

コード内の動的多型をかなり大きなクラスに置き換える必要があり、CRTP +可変テンプレート設計に問題があります。CRTP +可変テンプレートによる動的多型の模倣

説明すると、私は以下のおもちゃの問題を提供します。

次のインターフェイスが使用されているように、動的多型クラスがある:

int main() { 
    Loop loop; 
    Add add ; 
    loop.set(add); 
    loop.run(); 
    Sub sub ; 
    loop.set(sub); 
} 
もちろん

SubAddがベースクラスOperationop(double & v)から誘導されるが仮想メソッドです。

静的ポリモーフィズムにより、動的に変化させながら、私は、他の理由のために、このインターフェイスを維持する必要がある、これは今まで私のソリューションです:

template <typename T> class Operation { 
public: 
    double d=1.; 
    void op(double & d) { static_cast<T*>(this)->op(d);} 
}; 
class Add final: public Operation<Add> { 
public: void op(double & v) { v += d; } 
}; 
class Sub final: public Operation<Sub> { 
public: void op(double & v) { v -= d; } 
}; 

Loopクラスのため:

template <typename... Types> 
class MetaLoop { 
public: 
    double d = 0 ; 
    template <typename T> void set(T & t) { 
    std_cxx17::get<std::vector<T*> >(data).push_back(&t) ; 
    } 
    template <typename T> void run() { 
    for (auto j = 0; j<2E9 ; ++j) 
     std_cxx17::get<std::vector<T*> >(data).back()->op(d); 
    std::cout << d << std::endl; 
    } 
private: 
    std::tuple<std::vector<Types*>... > data ; 
}; 
typedef MetaLoop<Add,Sub> Loop ; 

std_cxx17::get<T*>(data)は、型によって要素をタプル単位で選択するメソッドへの呼び出しです。this post

このソリューションは、しかし、私はtypedef MetaLoop<Add,Sub> Loop

ほとんど私はrun()にテンプレート引数を提供する必要性を除きたいインタフェース、すなわちrun<Add>run<Sub>MetaLoopからレジスタAddSubへの必要性を考え必要ですそれが、マクロを使用せずに、可能であるかどうかを知りたい:

  1. が自動的MetaLoopOperation<T>クラスを登録します(つまり、自動的にtypedef Metaloop<...operations...>と呼びます)
  2. runメソッドにテンプレートクラスを指定しないでください。 (run<Add>()の代わりにrun()を呼び出してください)
  3. このメソッドをライブラリから取得します。この種の多型性を静的に提供できるライブラリ(Boostなど)はありませんか?

私が使用できるいくつかの他のアーキテクチャがあることを認識していますが、他にも多くの制約があります。これは単なるおもちゃの問題です。

ありがとうございます!

EDIT 1:

質問2回答されています!ここを参照してください:http://coliru.stacked-crooked.com/a/e68ea7faabba3e40

賛辞をhttps://www.reddit.com/user/17b29a

+0

「Add」を明示的に指定しないと、何が実行されると思いますか? 'Add'と' Sub'の両方を実行するべきでしょうか? – skypjack

+0

私はそれが設定されている最後のタイプを実行することを期待しています。ありがとう! – Astor

+0

だから、毎回アクティブなタイプが1つしかないと思っていますか?なぜ、すべてをベクターに保存するのですか? – skypjack

答えて

0

にあなたは次の例のようにあなたのタイプをタイプ-消去することができます:

#include <iostream> 
#include <vector> 
#include <utility> 

template<typename T> 
struct Operation { 
    void op(double &d) { static_cast<T*>(this)->op(d) ; } 
    double d{1}; 
}; 

struct Add: Operation<Add> { 
    void op(double &v) { v += d; } 
}; 

struct Sub: Operation<Sub> { 
    void op(double &v) { v -= d; } 
}; 

class Loop { 
    using Fn = void(*)(double &, void *); 

    template<typename T> 
    static void op(double &d, void *op) { 
     static_cast<T*>(op)->op(d); 
    } 

public: 
    template<typename T> 
    void set(T &t) { 
     data.emplace_back(&op<T>, &t); 
    } 

    void run() { 
     auto &p = data.back(); 
     for(auto j = 0; j < 10; ++j) { 
      p.first(d, p.second); 
     } 

     std::cout << d << std::endl; 
    } 

private: 
    std::vector<std::pair<Fn, void*>> data; 
    double d = 0; 
}; 

int main() { 
    Loop loop; 
    Add add; 
    loop.set(add); 
    loop.run(); 
    Sub sub; 
    loop.set(sub); 
    // ... 
} 

も注意ことが、この場合には、CRTPのイディオムは無用ですテンプレートクラスOperationを削除することができます。それは次のように
は単にAddSubを定義します。

struct Add { 
    void op(double &v) { v += d; } 
    double d{1}; 
}; 

struct Sub { 
    void op(double &v) { v -= d; } 
    double d{1}; 
}; 

あなたはAddSubを区別し、異なるアルゴリズムを提供したい場合は、特殊化を使用することができます。

class Loop { 
    using Fn = void(*)(double &, void *); 

    template<typename T> 
    static void op(double &d, void *op); 

public: 
    template<typename T> 
    void set(T &t) { 
     data.emplace_back(&op<T>, &t); 
    } 

    void run() { 
     auto &p = data.back(); 
     for(auto j = 0; j < 10; ++j) { 
      p.first(d, p.second); 
     } 

     std::cout << d << std::endl; 
    } 

private: 
    std::vector<std::pair<Fn, void*>> data; 
    double d = 0; 
}; 

template<> 
void Loop::op<Add>(double &d, void *op) { 
    Add *add = static_cast<Add*>(op); 
    // do whatever you want with add 
    add->op(d); 
} 

template<> 
void Loop::op<Sub>(double &d, void *op) { 
    Sub *sub = static_cast<Sub*>(op); 
    // do whatever you want with sub 
    sub->op(d); 
} 

注ソリューションは、質問に記載されているすべての要件と一致し、それがOPで例として提供mainで動作していること:例として

+0

ありがとう@skypjack! 残念ながら、私のオブジェクト 'Add'と' Sub'は、私の例で示されているよりもはるかに複雑で、ループでそれらと何をするかは、示されているよりはるかに複雑です。したがって、私は実際にそれらへのポインタにアクセスする必要があります。 私はそれがかなりきれいだと思うインターフェイスを修正する答えを得ました!私はすべての 'Operation 'のスペシャライゼーションをインスタンス化する方法が必要です。すべてが解決されるでしょう! :-) – Astor

+0

@Astor私の例では、実際には_accessing_にそれらのポインタに。 'loop'に' op'メソッドの実装を見て、オブジェクトを元の型にキャストします。 – skypjack

+0

@Astor答えに詳細を追加しました。それが明らかであれば教えてください。この場合、厳密には要求されていなくても、必要に応じてCRTPを使用することができます。 – skypjack

関連する問題