2011-07-20 7 views
1

これは、ここ数日間、実際に私を殺しています。 私は効果的にSzymon Gatnerが彼の素晴らしい記事で説明したように、hereを見つけました。 (そこのデモコードのEventHandlerクラスをチェックしてください)デコレート可能な効果的なイベント処理のタイプをC++で作成する

拡張可能なインターフェイスでタイプを作成する方法については、私がウェブで見つけた数少ない記事の1つです。私は特に使用法の構文が好きで、理解しやすいものでした。

しかし、私はもう1つこのタイプでやりたいことがあります、それはそれを装飾できるようにすることです。今、余分なデータメンバでそれを飾ることは一つのことですが、私は装飾がインターフェイスを拡張することを許可したいと思います。EventHandler :: handleEventは公に公開する必要のある唯一のメソッドです。

残念ながら、EventHandler :: registerEventFuncメソッドはテンプレート化されています。 これは、HandlerBaseのように、EventHandlerが継承するさらに基本的なクラスでは、仮想メソッドとして定義できないことを意味します。

私の質問は、誰かが問題を解決する方法(EventHandlerを装飾可能にする)に関する良いアイデアを持っているかどうかです。

私が試した作成方法

1)

void registerEventFunc(boost::function<void()> * _memFn); 

及び2)

void registerEventFunc(boost::function<void(*SomeDerivedEvent*)> * _memFn); 

及び3)

void registerEventFunc(boost::function<void(EventBase*)> * __memFn); 

Foをr 1、それを行うと、コールバックのクラスEvent derived argument型のtypeidが失われます。 2の場合、登録時にこのクラスが予定している多くのイベントコールバックの関数をオーバーロードしなければならない3では、多型はテンプレートパラメータで機能しません。

ファンクションの仮想化を可能にする最も近いのは1で、 ですが、boost :: functionオブジェクトの作成時に引数をバインドして使用することができません後でEventHandler :: handleEventの本体でラムダを使用します。

class FooEvent : public Event 
{ 
    public: 
    FooEvent(int _val) : Event(), val(_val){} 
    int val; 
}; 


class MyHandler : public EventHandler 
{ 
    public: 
    MyHandler() 
    { 
    registerEventFunc(new boost::function<void()>(boost::bind(boost::mem_fn(&MyHandler::onEvent),this, new FooEvent(5)))); 
    } 

    void onEvent(const FooEvent * _event) 
    { 
    cout << _event->val << endl; 
    } 

}; 

最終的に、私は(それが全体のTypeInfoビジネスがマップ検索のためのキーを作成することを把握することはできません)にもかかわらず動作するとは思わない

任意のアイデアをいただければ幸いです!

私がこれを間違った方法で行っている場合、私は代替案の言及に感謝します。 もちろん、ゴールはデータのメンバーだけでなくパブリックインターフェイスも簡単に拡張できる装飾可能な型を持つことです。 私はSzymonのものが第2の半分が既に終わったように思えたので、良い出発点だったと思った。

ありがとうございました。

答えて

3

おそらく1つのオプションは、実際にハンドラを登録するための情報を入力し保持するテンプレートパブリック関数に加え、仮想保護された関数を作成することです。つまり:

class event_source { 
    protected: 
    struct EventAdapter { 
     virtual void invoke(EventBase *) = 0; 
     virtual ~EventAdapter() { } 
    }; 
    template<typename EventParam> 
    struct EventAdapterInst : public EventAdapter { 
     boost::function<void(const EventParam &)> func_; 

     EventAdapterInst(const boost::function<void(const EventParam &)> &func) 
     : func_(func) 
     { } 

     virtual void invoke(EventBase *eb) { 
     EventParam *param = dynamic_cast<EventParam *>(eb); 
     assert(param); 
     func_(*param);   
     } 
    }; 
    virtual void register_handler(std::type_info param_type, EventAdapter *ea); 
    public: 
    template<typename EventParam> 
     void register_handler(const boost::function<const EventParam &> &handler) 
     { 
     register_handler(typeid(EventParam), new EventAdapterInst(handler)); 
     } 
}; 

派生クラステンプレート関数の型推論のプロパティを壊すことなく、彼らが好きなものは何でもする仮想register_handlerを上書きすることができます。

+0

非常に興味深い。 私がすでに書いたテストコードにこれらのアイデアを適用できるかどうか確認したいと思います。私は1日ほどであなたに戻ってきます。 – sbrett

+0

これは私の問題に対する有効かつ有効な解決策であることが確認できます。それは非常にうまく機能し、タイプのデザインを続けることができました。私はまだそれを完了していないが、それは私が立ち往生した部分を越えさせることができた。今私はそれについて考えて、私は最初にそれを見ていないと驚いています。私は今、それにデコレータパターンを追加する過程にあり、それは驚くほどうまく収まります。この1つのbdonlanであなたに大きなアップ。私はあなたにもっと信用を与えることができれば幸いです。私は非常に助けに感謝します。 – sbrett

関連する問題