1

私は Curiously Recurring Template パターンを調査して、それを使用して Bridge Design パターンを実装する方法を決定しました。

私の問題は、オーバーライドするメソッドが実際にテンプレート化されているため、IBridgeConnector::GetBridgeImpl メソッドを Bridge::GetBridgeImpl メソッドに接続 (接続) することです。

この場合、仮想ディスパッチは機能しないため、これらのメソッドを相互にポイントする最良の方法は何ですか? 関数デリゲート? これにはより良いパターンがありますか?

これはどのように行うべきですか?

助けてくれてありがとう!

どこでも shared_ptrs と OpenGL および DirectX 呼び出しなしでできる限りのコードの簡素化を行いました。:) うまくいけば、これは将来誰かに役立つでしょう!

#include <string>
/********************************************************************/
class BridgePart
{
public:
    BridgePart * OtherPart;
};

/********************************************************************/
// Connects a BridgeSource and a BridgeImplementation
class BridgeConnector
{
public:
    static BridgeConnector * implementor;

    // Need a way, (Function Delegates?) to point this method
    // This method will loop until stack overflow.
    template <typename ValueTemplateType>
    BridgePart * GetBridgeImpl(ValueTemplateType * source)
    {
        return implementor->GetBridgeImpl<ValueTemplateType>(source);
    }
};
BridgeConnector * BridgeConnector::implementor = nullptr;

/********************************************************************/
// Where the Magic is At, (CRTP)
template <typename BridgeImplementationTemplateType>
class Bridge : public BridgeConnector
{
public:
    template <typename ValueTemplateType>
    IBridgePart * GetBridgeImpl(IBridgePart * source)
    {
        // NOTE:  This method never gets called.
        // CRTP Magic Here to Semi-Specify Pure Virtual Methods
        return static_cast<BridgeImplementationTemplateType>(this)
            ->GetBridgeImpl( (ValueTemplateType) source);
    }
};

/********************************************************************/
class BridgeImplementation1 : 
    public Bridge<BridgeImplementation1>,
    public BridgePart
{
public:
    class CustomImpl : public BridgePart
    {
    public:
        template <typename SourceTemplateType>
        BridgePart(SourceTemplateType source){}
            /* Does proprietary stuff. */
    };

    template <typename ValueTemplateType>
    BridgePart * GetBridgeImpl(ValueTemplateType & source)
    {
        return new CustomImpl<ValueTemplateType>(source);       
    }
    // Constructor
    BridgeImplementation1()
    {
    }
};

/********************************************************************/
class BridgeSource1 : public BridgePart {};
class BridgeSource2 : public BridgePart {};
class Client
{
    BridgeSource1 source1;
    BridgeSource2 source2;
    BridgeConnector * connector;
    bool usingImpl1;

    Client()
    {
        usingImpl1 = true; // from config file.
        connector = new BridgeConnector();
        connector->implementor = usingImpl1 
            ? (BridgeConnector *) new BridgeImplementation1()
            : nullptr; // (BridgeConnector *) new BridgeImplementation2();  
        // removed to shorten code.
    }

    void Init()
    {
        source1.OtherPart = connector->GetBridgeImpl<BridgeSource1>(& source1);
        source2.OtherPart = connector->GetBridgeImpl<BridgeSource2>(& source2); 
    }
};
4

2 に答える 2

3

関数を呼び出すときLoadDriver、テンプレート パラメータは、つまりポインタです。ブリッジ実装クラスには、ポインターを取らない関数があります。そのため、コンパイラが一致する関数を見つけようとするとき、ポインター以外の引数を取る関数は考慮せず、ポインター引数を取る関数のみを考慮します。Client::InitValueTemplateTypestd::string*BridgeImplementation1BridgeImplementation2LoadDriver

とのLoadDriver関数をポインタ引数を取るように変更する必要があります。BridgeImplementation1BridgeImplementation2

于 2013-02-06T07:13:22.787 に答える
3

CRTPについて少し誤解していると思います。仮想ディスパッチのプラグイン代替品ではありません。あなたの場合、IBridge には仮想ディスパッチがないため、IBridge->LoadDriver を呼び出すと、基になる派生クラスに関係なく、常にデフォルトの基本クラスの実装が提供されます。汎用インターフェースが必要な場合は、ある種の仮想ディスパッチが必要です。CRTP は、基本クラスのメンバー関数が他の仮想関数を呼び出す場合など、必要のない場合に仮想ディスパッチを回避する方法にすぎません。

仮想ディスパッチを完全に回避したい場合は、ブリッジからクライアントを完全に切り離すことはできません。ブリッジでクライアントをテンプレート化する必要がありますが、これは派生でテンプレート化するよりも実際には何の利点もありません。

これがあなたが望むことをするためのショットです。Bridge は CRTP を使用して解釈し、BridgeImpl に渡します。明らかに、この時点で、引数のタイプ セーフのすべての希望を放棄しました。

class IBridge {
    virtual void LoadDriver(void *) = 0;
};

template <typename Impl>
class Bridge : public IBridge {
    void LoadDriver(void * v) override {
        static_cast<Impl*>(this)->LoadDriverImpl(*static_cast<Impl::arg_type *>(v));
    }
};

class BridgeImpl : public Bridge<BridgeImpl> {
    typedef std::string arg_type;
    void LoadDriverImpl(const std::string & s){ /*...*/ }
};
于 2013-02-06T07:21:41.850 に答える