2011-07-30 2 views
3

私のゲームのイベントシステムを作成しようとしています。私のイベントマネージャーが保存するコールバックは、単純関数とファンクターの両方になります。私はまた、関数/ファンクタを比較できるようにする必要があるので、どのイベントマネージャをイベントマネージャから切断する必要があるのか​​分かります。メッセージングシステム:コールバックは何でもかまいません

•最初はboost :: functionを試しました。関数とファンクタは完全にうまく処理されますが、演算子==がないことを除けば、コールバックを削除することはできません。

class EventManager 
{ 
    typedef boost::function<void (boost::weak_ptr<Event>)> Callback; 
    std::map<Event::Type, std::vector<Callback>> eventHandlerMap_; 
}; 

==私はまた、::ブーストを使用して信号を試してみましたが、それはまた、私のオペレータに関連したコンパイルの問題を与えます。「==」バイナリ

:なし演算子は左をとる見つかりません-handタイプのオペランド「のconstのFunctor」(あるいは全く許容可能な変換はありません)

void test(int c) { 
    std::cout << "test(" << c << ")"; 
} 

struct Functor 
{ 
    void operator()(int g) { 
     std::cout << "Functor::operator(" << g << ")"; 
    } 
}; 

int main() 
{ 
    boost::signal<void (int)> sig; 

    Functor f; 

    sig.connect(test); 
    sig.connect(f); 

    sig(7); 

    sig.disconnect(f); // Error 
} 

私はこれを実装する方法をについての他の提案?あるいは、私はboost :: functionまたはboost :: signalのどちらを使うことができるのでしょうか?これは私がEventManagerが欲しいというのインタフェースである:


編集(。私は信号を聞いたので、私はむしろ、アイテムの小さなコレクションのかなり遅いです、しかしブースト::機能を使用すると思います)持つ。

class EventManager 
{ 
    public: 
    void addEventHandler(Event::Type evType, Callback func); 
    void removeEventHandler(Event::Type evType, Callback func); 

    void queueEvent(boost::shared_ptr<Event> ev); 
    void dispatchNextEvent(); 
}; 
+0

@bdonlan信号例のものは[boost :: function_equal](http://www.boost.org/doc/libs/1_47_0/doc/html/boost/function_equal.html)です。 –

+0

sorta dup:http://stackoverflow.com/questions/89488/comparing-stdtr1function-objects – stijn

答えて

1

問題はありませんでした。少しテンプレート魔法と物事がシンプルになる(R):

template<typename F> 
void EventManager::removeEventHandler(Event::Type evType, F func) 
{ 
    auto compare = [func](const Callback& other) -> bool { 
     F const* f = other.target<F>(); 
     if (f == nullptr) return false; 
     return *f == func; 
    }; 

    std::vector<Callback>& callbacks = ...; 
    auto pend = std::remove_if(callbacks.begin(), callbacks.end(), compare); 
    callbacks.erase(pend, callbacks.end()); 
} 


template<typename R, typename F, typename L> 
void EventManager::removeEventHandler(
    Event::Type evType, const boost::_bi::bind_t<R, F, L>& func) 
{ 
    auto compare = [&func](const Callback& other) -> bool { 
     auto const* f = other.target<boost::_bi::bind_t<R, F, L>>(); 
     if (f == nullptr) return false; 
     return func.compare(*f); 
    }; 

    std::vector<Callback>& callbacks = ...; 
    auto pend = std::remove_if(callbacks.begin(), callbacks.end(), compare); 
    callbacks.erase(pend, callbacks.end()); 
} 

私はoperator==が実際にバインド・オブジェクトの比較を行うが、その結果を比較して、新たなファンクタを生成しないのでBoost.Bindオブジェクトを別々に処理する必要があります他の2つ(read more)。 Boost.Bindを比較するには、メンバー関数compare()を使用する必要があります。

タイプboost::_bi::bind_tは、ブーストの内部型のようです、しかし、また、このタイプを使用boost::function_equalのすべてのオーバーロードとしてそれを使用しても安全でなければなりません(referenceを)(私はそれが「_bi」という意味の名前空間にアンダースコアが何だと思います) 。

このコードはoperator==と定義されていれば、と定義されているか、Boost.Bindを使用している場合は、すべてのタイプのファンクタで動作します。私はstd::bind(C++ 0x)の表面的な見た目を持っていましたが、それは匹敵するとは思われませんので、上記のコードではうまくいきません。

1

ほとんどの汎用関数ラッパーは関数の等価性をサポートしていません。

これはなぜですか?まあ、ちょうどそこにあなた数子を見て:

struct Functor 
{ 
    void operator()(int g) { 
     std::cout << "Functor::operator(" << g << ")"; 
    } 
}; 

このFunctorにはoperator==持っていないので、等しいかどうかを比較することはできません。したがって、boost::signalに値を渡すと、新しいインスタンスが作成されます。これは、ポインタの等価性についてfalseを比較し、値の等価性をテストする演算子を持たない。

ほとんどのファンクタは、実際には、値等価述語を持っていません。これはあまり役に立ちません。これを処理する通常の方法は、代わりにコールバックを処理することです。 boost :: signalsはconnectionオブジェクトでこれを行います。例えば、the documentationからこの例を見てみましょう:これにより

boost::signals::connection c = sig.connect(HelloWorld()); 
if (c.connected()) { 
// c is still connected to the signal 
    sig(); // Prints "Hello, World!" 
} 

c.disconnect(); // Disconnect the HelloWorld object 
assert(!c.connected()); c isn't connected any more 

sig(); // Does nothing: there are no connected slots 

HelloWorldを使用すると、信号の登録を直接参照しているとして、operator==を持っている必要はありません。

+0

接続オブジェクトを保存する場合は、代わりにベクトルを使用し、イテレータを保存することもできますその代わりに、関数は信号より高速です。代わりにboost :: functionがメモリアドレスを比較する方法はありませんか? –

+0

'boost :: function'も値で取り込みますので、アドレスは同じではありません。そして、私は、信号が通常の関数ベクトルよりもあまり悪くないとは思わない。 – bdonlan

1

libsigcとlibsigC++を試したことがありますか?私はそれらをLinuxで使い始めて、彼らと恋に落ちました。私は今でも私のWindowsアプリケーションでそれらを使用します。私はそれがブーストよりも拡張性と柔軟性があると信じています。実装するのも簡単です。

1

Don Clugstonの "Member Function Pointers and Possible C++ Delegates"をお勧めします。あなたが記事を見つけて、ここからコードをダウンロードすることができます他の多くの利点の中

http://www.codeproject.com/KB/cpp/FastDelegate.aspx

を、彼の代表団は、箱から出して比較演算子(!==、=、<)を提供します。私は現在、それらをリアルタイムシステムに使用しており、あらゆる点で優れていることがわかります。私は、コンパイラの移植性の問題を修正するために軽微な変更を加えなければならないことを思い出しているようです。その経験はプラットフォームなどによって異なります

また、この記事は数年前です。問題が発生した場合は、このデリゲートの実装に関する更新されたコード/ディスカッションについては、Googleをご利用ください。

関連する問題