2008-09-18 19 views
5

की तुलना में मैं सी ++ में एक सी #-जैसी घटना प्रणाली को कार्यान्वित करने का प्रयास कर रहा हूं जिसमें tr1 फ़ंक्शन टेम्पलेट्स को ईवेंट को संभालने वाले फ़ंक्शन को संग्रहीत करने के लिए उपयोग किया जाता है।std :: tr1 :: function <> ऑब्जेक्ट्स

मैं इतना है कि कई श्रोताओं, इस घटना से जुड़ी किया जा सकता है एक वेक्टर बनाई यानी .:

vector< function<void (int)> > listenerList; 

मैं सूची में से एक हैंडलर दूर करने के लिए एक श्रोता की घटनाओं प्राप्त करना बंद करने में सक्षम होना चाहते हैं।

तो, मैं इस सूची में प्रवेश कैसे प्राप्त कर सकता हूं जो किसी दिए गए श्रोता से मेल खाता है? क्या मैं परीक्षण कर सकता हूं कि सूची में 'फ़ंक्शन' ऑब्जेक्ट किसी विशेष फ़ंक्शन को संदर्भित करता है?

धन्यवाद!

संपादित करें: बूस्ट :: सिग्नल दृष्टिकोण में ध्यान देने के बाद, ऐसा लगता है कि यह शायद टोकन सिस्टम का उपयोग करके कार्यान्वित किया गया है क्योंकि आप में से कुछ ने सुझाव दिया है। Here's some info on this। एक पर्यवेक्षक एक घटना से संलग्न होने पर "कनेक्शन" ऑब्जेक्ट को बरकरार रखता है, और यदि आवश्यक हो तो यह कनेक्शन ऑब्जेक्ट डिस्कनेक्ट करने के लिए उपयोग किया जाता है। तो ऐसा लगता है कि आप बूस्ट का उपयोग करते हैं या tr1 के साथ अपना खुद का रोल करते हैं, मूलभूत सिद्धांत वही है। यानी यह थोड़ी बेकार होगी :)

उत्तर

2

FAQ #1 बूस्ट फ़ंक्शन प्रलेखन में आपके प्रश्न को संबोधित करने लगता है - और आसान जवाब "नहीं" है।

1

proposal (सेक्शन IIIb।) कहता है कि वे किसी भी तरह से तुलनीय नहीं होंगे। यदि आप उन्हें कुछ अतिरिक्त जानकारी संलग्न करते हैं, तो आप आसानी से प्रत्येक कॉलबैक की पहचान कर सकते हैं। उदाहरण के लिए, यदि आप फ़ंक्शन पॉइंटर को लपेटने वाली संरचना को परिभाषित करते हैं, तो आप उन्हें हटा सकते हैं (माना जाता है कि आपके पास उसी स्ट्रक्चर को डाला गया है)। आप संरचना में कुछ फ़ील्ड भी जोड़ सकते हैं (जैसे स्वचालित रूप से जेनरेट किए गए मार्गदर्शिका क्लाइंट को पकड़ सकते हैं) और इसके विरुद्ध तुलना करें।

+0

आप अतिरिक्त जानकारी के साथ एक struct का उपयोग करने के लिए जा रहे हैं, तो आप के रूप में अच्छी functors हैश मान के रूप में GUID/जो कुछ भी रूप में हैश कुंजी की दुकान है, और हो सकता है। :-) –

+0

आप फ़ैक्टर को हैश मानों के रूप में स्टोर नहीं कर सकते हैं। आप उनके साथ कुछ भी नहीं कर सकते हैं। उन्हें एक संरचना में लपेटना (यहां तक ​​कि केवल मज़ेदार की एक तत्व संरचना) आपको कुछ भी करने की अनुमति देगा। यह जानबूझकर है कि कुछ काम किए बिना उनकी तुलना/ढीला/आदि नहीं किया जा सकता है। – hazzen

0

यदि आप केवल फ़ंक्शन पॉइंटर्स संग्रहीत कर रहे हैं (और अन्य फ़ैक्टर जो आवश्यक हस्ताक्षर से मेल खाते हैं), यह आसान है (नीचे कोड देखें)। लेकिन आम तौर पर, उत्तर, अन्य पोस्टर की तरह जवाब ने कहा है, नहीं। उस स्थिति में, आप संभवत: अपने मज़ेदारों को हैश में, मूल्यों के रूप में स्टोर करना चाहते हैं, चाबियां उपयोगकर्ता को जोड़ने और निकालने पर कुछ आपूर्ति करती हैं।

नीचे दिया गया कोड दर्शाता है कि कैसे मज़ेदार/पॉइंटर ऑब्जेक्ट को कॉल किया जाना है। इसका उपयोग करने के लिए, आपको निकालने के लिए ऑब्जेक्ट का सटीक प्रकार पता होना चाहिए (यानी, आपके द्वारा निर्दिष्ट प्रकार के typeid निहित मज़ेदार/सूचक के typeid से मेल खाना चाहिए)।

#include <cstdio> 
#include <functional> 

using std::printf; 
using std::tr1::function; 

int main(int, char**); 
static function<int (int, char**)> main_func(&main); 

int 
main(int argc, char** argv) 
{ 
    printf("%p == %p\n", *main_func.target<int (*)(int, char**)>(), &main); 
    return 0; 
} 
0

क्या

के बारे में
map<key-type, function<void (int)> > listeners; 
+0

मुझे लगता है कि एक हैश (std :: tr1 :: unordered_map) इस तरह की चीज़ के लिए बेहतर विकल्प है। पंजीकरण के क्रम में श्रोताओं को कॉल करना महत्वपूर्ण नहीं है, इस मामले में कुंजी प्रकार में एक सीरियल नंबर शामिल होना चाहिए। –

4

ठीक है, तुम मुझे काम कर गया। कठिन हिस्सा सी # घटनाओं के सटीक उपयोग पैटर्न से मेल खाने का प्रयास कर रहा है। यदि आप इसे छोड़ देते हैं, तो आप जो भी पूछ रहे हैं उसे करने के लिए बहुत आसान तरीके हैं। (मेरा सहकर्मी जेसन पूरे स्थान पर एक नोटिफ़ायर ऑब्जेक्ट का उपयोग करता है।) वैसे भी, यहां अविश्वसनीय रूप से उबाऊ कोड है जो आप चाहते हैं। दुर्भाग्यवश, यह आपको विषय से ऑब्जर्वर तक पैरामीटर पास करने की अनुमति नहीं देता है। ऐसा करने के लिए, आपको और भी स्मारक जोड़ने की आवश्यकता होगी।

घटना

किया कर घटना
..observed कर:

#include "stdafx.h" 
#include <iostream> 
#include <string> 
#include <list> 
#include <algorithm> 
#include <boost/tr1/functional.hpp> 
#include <boost/tr1/memory.hpp> 

using namespace std; 
using namespace std::tr1; 

template <typename T> 
class ObserverHandle 
{ 
public: 
    typedef boost::function<void (T*)> const UnderlyingFunction; 

    ObserverHandle(UnderlyingFunction underlying) 
     : _underlying(new UnderlyingFunction(underlying)) 
    { 
    } 

    void operator()(T* data) const 
    { 
     (*_underlying)(data); 
    } 

    bool operator==(ObserverHandle<T> const& other) const 
    { 
     return (other._underlying == _underlying); 
    } 

private: 
    shared_ptr<UnderlyingFunction> const _underlying; 
}; 

class BaseDelegate 
{ 
public: 
    virtual bool operator==(BaseDelegate const& other) 
    { 
     return false; 
    } 

    virtual void operator()() const = 0; 
}; 

template <typename T> 
class Delegate : public BaseDelegate 
{ 
public: 
    Delegate(T* observer, ObserverHandle<T> handle) 
     : _observer(observer), 
     _handle(handle) 
    { 
    } 

    virtual bool operator==(BaseDelegate const& other) 
    { 
     BaseDelegate const * otherPtr = &other; 
     Delegate<T> const * otherDT = dynamic_cast<Delegate<T> const *>(otherPtr); 
     return ((otherDT) && 
      (otherDT->_observer == _observer) && 
      (otherDT->_handle == _handle)); 
    } 

    virtual void operator()() const 
    { 
     _handle(_observer); 
    } 

private: 
    T* _observer; 
    ObserverHandle<T> _handle; 
}; 

class Event 
{ 
public: 
    template <typename T> 
    void add(T* observer, ObserverHandle<T> handle) 
    { 
     _observers.push_back(shared_ptr<BaseDelegate>(new Delegate<T>(observer, handle))); 
    } 

    template <typename T> 
    void remove(T* observer, ObserverHandle<T> handle) 
    { 
     // I should be able to come up with a bind2nd(equals(dereference(_1))) kind of thing, but I can't figure it out now 
     Observers::iterator it = find_if(_observers.begin(), _observers.end(), Compare(Delegate<T>(observer, handle))); 
     if (it != _observers.end()) 
     { 
      _observers.erase(it); 
     } 
    } 

    void operator()() const 
    { 
     for (Observers::const_iterator it = _observers.begin(); 
      it != _observers.end(); 
      ++it) 
     { 
      (*(*it))(); 
     } 
    } 

private: 
    typedef list<shared_ptr<BaseDelegate>> Observers; 
    Observers _observers; 

    class Compare 
    { 
    public: 
     Compare(BaseDelegate const& other) 
      : _other(other) 
     { 
     } 

     bool operator() (shared_ptr<BaseDelegate> const& other) const 
     { 
      return (*other) == _other; 
     } 

    private: 
     BaseDelegate const& _other; 
    }; 
}; 

// Example usage: 

class SubjectA 
{ 
public: 
    Event event; 

    void do_event() 
    { 
     cout << "doing event" << endl; 
     event(); 
     cout << "done" << endl; 
    } 
}; 

class ObserverA 
{ 
public: 
    void test(SubjectA& subject) 
    { 
     subject.do_event(); 
     cout << endl; 

     subject.event.add(this, _observe); 
     subject.do_event(); 
     subject.event.remove(this, _observe); 
     cout << endl; 

     subject.do_event(); 
     cout << endl; 

     subject.event.add(this, _observe); 
     subject.event.add(this, _observe); 
     subject.do_event(); 
     subject.event.remove(this, _observe); 
     subject.do_event(); 
     subject.event.remove(this, _observe); 
     cout << endl; 

    } 

    void observe() 
    { 
     cout << "..observed!" << endl; 
    } 

private: 
    static ObserverHandle<ObserverA> _observe; 
}; 

// Here's the trick: make a static object for each method you might want to turn into a Delegate 
ObserverHandle<ObserverA> ObserverA::_observe(boost::bind(&ObserverA::observe, _1)); 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    SubjectA sa; 
    ObserverA oa; 
    oa.test(sa); 

    return 0; 
} 

और यहाँ उत्पादन है!
किया

घटना

किया घटना
..observed कर कर रही है!
..observed!
किया
घटना कर रहे हैं
..observed!

8

अगर आप एसटीडी सी ++ और tr1 में लॉक हो जाता है मैं नहीं जानता कि क्या किया, लेकिन यदि आप नहीं कर रहे हैं, ऐसा लगता है जैसे आपकी समस्या को पूरी तरह से बचा जा सकता है अगर आप सिर्फ बढ़ावा तरह कुछ इस्तेमाल किया :: सिग्नल और बूस्ट :: अपनी मूल समस्या को हल करने के लिए बाध्य करें - एक ईवेंट सिस्टम बनाना - अपने आप को रोल करने की कोशिश करने के बजाय।

+1

हां, पेड़ के बावजूद वन देखना महत्वपूर्ण है, इसलिए बोलना। उत्तर देने के लिए धन्यवाद कि मेरी इच्छा है कि मैं सोचने के लिए वापस कदम रखा था! –

0

मुझे एक ही समस्या थी और इसे हल किया गया। मैंने कुछ सी ++ 0x विशेषताओं का उपयोग किया, लेकिन केवल सुविधा के लिए, वे एक आवश्यक हिस्सा नहीं हैं। यहाँ एक नज़र डालें:
>Messaging system: Callbacks can be anything