6

(C++ で) テンプレート化されたメンバー関数 (非テンプレート クラスの) を仮想にしたいという設計上の問題が発生しており、問題を回避する適切でエレガントな方法があるかどうか疑問に思っています。

シナリオは次のとおりです。一般的なアイテム処理する機械があります。各マシンが独自の処理方法を定義できるように、仮想プロセス (アイテム)関数を備えたマシンの抽象基本クラスを使用します。問題は、アイテムが処理方法について特定のインターフェイスを公開するという点で、アイテムも「一般的」であることです。理由から (主にパフォーマンスのため... vtable のオーバーヘッドがないため)、これらのアイテムにはコンパイル時のポリモーフィズムを使用したいと思います。これで、各マシンは次のようなインターフェイスを持つようになります。

class Machine
{ public:
    template <typename T>
    virtual void process(T& item) = 0; 
};

ただし、テンプレート化されたメンバー関数は仮想化できないため、これは C++ では不可能です。確かに、Item タイプ T でテンプレート化されたマシン クラスを作成できますが、これにより、より大きな設計スキームでさらに頭痛の種が増え、実際には Machine クラスの他の部分は Item に依存しません...それは process() 関数の引数にすぎません.

これを回避するより良い方法、または汎用アイテムのファミリを処理するこの種の汎用マシン ファミリを提供する方法についての提案はありますか (アイテムはコンパイル時のポリモーフィズムを使用します)。私は私のデザインの面で深いところから外れていますか?

提案に感謝します

4

1 に答える 1

3

通常、二重ディスパッチが使用されます。

class Machine;
class Item {
public:
    virtual void bounce(Machine& mach);
};
class Machine {
public:
    template<typename T> void process(T& t);
    virtual void process(Item& i) {
        return i.bounce(*this);
    }
};
template<typename T> class CRTPItem {
public:
    virtual void bounce(Machine& mach) {
        return mach.process(*(T*)this);
    }
};
class ConcreteItem : public CRTPItem<ConcreteItem> {
public:
    // blah blah
};

bounceこの場合、 ConcreteItemインターフェイス全体の仮想オーバーヘッドは必要ありません。また、共通のものも必要ありませんCRTPItem。Item のすべての関数に対して vtable 呼び出しが必要であるのとは対照的に、これは最初にあったものとは対照的に 2 つの vtable 呼び出しだけであり、インターフェースは、仮想テンプレートを作成できた場合に保持されるすべての厳密な型指定を引き続き保持できます。

于 2013-03-23T21:52:05.073 に答える