2011-07-30 8 views
3

게임용 이벤트 시스템을 작성하려고합니다. 내 이벤트 관리자가 저장할 콜백은 펑터뿐만 아니라 일반 함수가 될 수 있습니다. 또한 함수/펑터를 비교할 수 있어야하므로 이벤트 관리자와의 연결을 끊어야하는지 알 수 있습니다.메시징 시스템 : 콜백은 무엇이든 가능합니다

• 처음에는 boost :: function을 사용해 보았습니다. 함수와 펑터를 완벽하게 처리하지만, operator ==가 없기 때문에 원하는 경우 콜백을 제거 할 수 없습니다.

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

나는 또한 부스트 :: 신호를 사용했지만, 그 또한 나에게 운영자 == 관련 컴파일 문제가 있습니다 : •

는 '=='

진 : 어떤 운영자가 발견되지 왼쪽 소요 '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 work를 어떻게 만들 수 있을까요? (I 신호 오히려 항목의 작은 컬렉션 둔화되는 들었어요 때문에 차라리,하지만 부스트 :: 기능을 사용하십시오.)


편집 : 이것은 개의 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 별도로 개체를 처리해야 다른 두 개 (read more). Boost.Bind를 비교하려면 멤버 함수 compare()을 사용해야합니다.

유형 boost::_bi::bind_t 부스트의 내부 유형 것 같다, 그러나 또한이 유형을 사용 boost::function_equal의 모든 오버로드로 사용하는 것이 안전합니다 (reference)을 (난 그 '_bi'는 네임 스페이스에 밑줄이 무엇을 생각) .

으로 정의되고이 코드가 인 경우 또는 Boost.Bind를 사용하는 경우이 코드는 모든 유형의 펑터에서 작동합니다. 나는 std::bind (C++ 0x)에 피상적 인 모습을 보였으 나 그 코드는 비교할 수없는 것처럼 보이기 때문에 위에 게시 한 코드에서는 작동하지 않습니다.

1

가장 일반적인 함수 래퍼는 함수 평등을 지원하지 않습니다.

왜 이런가요? 음, 그냥 당신의 펑보고 :

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

Functor에는 operator==이 없습니다, 따라서 어떤지를 비교 할 수 없습니다. 따라서 boost::signal값을으로 전달하면 새 인스턴스가 만들어집니다. 이것은 pointer-equality에 대해 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++를 사용해 본 적이 있습니까? 나는 그들을 리눅스에서 사용하기 시작했고 그들과 사랑에 빠졌다. 지금은 Windows 응용 프로그램에서도 사용합니다. 나는 그것이 부스트보다 더 유연하고 유연하다고 믿습니다. 그것은 또한 구현하는 산들 바람입니다.

1

Don Clugston의 "멤버 함수 포인터 및 가능한 가장 빠른 C++ 대리인"을 적극 권장합니다.당신은 기사를 찾아 여기에서 코드를 다운로드 할 수 있습니다 많은 다른 혜택 중

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

는 그의 대표가 상자 밖으로 비교 연산자 (! ==, =, <)를 제공합니다. 저는 현재 실시간 시스템으로 사용하고 있으며 모든면에서 뛰어납니다. 컴파일러 이식성 문제를 해결하기 위해 사소한 수정을해야한다는 것을 상기하는 것 같습니다. 하지만 그 경험은 플랫폼에 따라 달라질 것입니다.

또한이 기사는 몇 년 된 것이므로 문제가 발생하면이 델리게이트 구현과 관련된 업데이트 된 코드/토론에 대해 Google을 참조하십시오.