Comparaison des objects std :: tr1 :: function

J’ai essayé d’implémenter un système d’événements de type C # en C ++ avec les modèles de fonction tr1 utilisés pour stocker une fonction qui gère l’événement.

J’ai créé un vecteur afin que plusieurs auditeurs puissent être associés à cet événement, à savoir:

vector< function > listenerList; 

J’aimerais pouvoir supprimer un gestionnaire de la liste pour empêcher un écouteur de recevoir des événements.

Alors, comment puis-je trouver l’entrée dans cette liste qui correspond à un auditeur donné? Puis-je tester si un object ‘fonction’ dans la liste fait référence à une fonction particulière?

Merci!

EDIT: Après avoir examiné l’approche boost :: signal, il semble qu’elle soit probablement mise en œuvre avec un système de jetons, comme certains l’ont suggéré. Voici quelques informations à ce sujet . Un observateur conserve un object “Connexion” lorsqu’il se connecte à un événement et cet object de connexion est utilisé pour se déconnecter si nécessaire. Donc, il semble que vous utilisiez Boost ou que vous rouliez vous-même avec tr1, le principe de base est le même. c’est à dire que ce sera un peu maladroit 🙂

Je ne sais pas si vous êtes bloqué dans std C ++ et tr1, mais si vous ne l’êtes pas, il semble que votre problème pourrait être complètement évité si vous utilisiez simplement quelque chose comme boost :: signal et boost :: bind pour résoudre votre problème. problème original – créer un système d’événements – au lieu d’essayer de lancer le vôtre.

Ok, tu me fais travailler. La partie difficile consiste à essayer de faire correspondre le modèle d’utilisation exact des événements C #. Si vous ignorez cela, il existe BEAUCOUP de moyens plus simples pour faire ce que vous demandez. (Mon collègue Jason utilise un object Notifier un peu partout.) Quoi qu’il en soit, voici le code incroyablement ennuyeux qui fait ce que vous voulez. Malheureusement, cela ne vous permet pas de passer des parameters de Subject à Observer. Pour ce faire, vous devrez append encore plus d’intelligence.

 #include "stdafx.h" #include  #include  #include  #include  #include  #include  using namespace std; using namespace std::tr1; template  class ObserverHandle { public: typedef boost::function const UnderlyingFunction; ObserverHandle(UnderlyingFunction underlying) : _underlying(new UnderlyingFunction(underlying)) { } void operator()(T* data) const { (*_underlying)(data); } bool operator==(ObserverHandle const& other) const { return (other._underlying == _underlying); } private: shared_ptr const _underlying; }; class BaseDelegate { public: virtual bool operator==(BaseDelegate const& other) { return false; } virtual void operator() () const = 0; }; template  class Delegate : public BaseDelegate { public: Delegate(T* observer, ObserverHandle handle) : _observer(observer), _handle(handle) { } virtual bool operator==(BaseDelegate const& other) { BaseDelegate const * otherPtr = &other; Delegate const * otherDT = dynamic_cast const *>(otherPtr); return ((otherDT) && (otherDT->_observer == _observer) && (otherDT->_handle == _handle)); } virtual void operator() () const { _handle(_observer); } private: T* _observer; ObserverHandle _handle; }; class Event { public: template  void add(T* observer, ObserverHandle handle) { _observers.push_back(shared_ptr(new Delegate(observer, handle))); } template  void remove(T* observer, ObserverHandle 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(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> Observers; Observers _observers; class Compare { public: Compare(BaseDelegate const& other) : _other(other) { } bool operator() (shared_ptr 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 _observe; }; // Here's the sortingck: make a static object for each method you might want to turn into a Delegate ObserverHandle ObserverA::_observe(boost::bind(&ObserverA::observe, _1)); int _tmain(int argc, _TCHAR* argv[]) { SubjectA sa; ObserverA oa; oa.test(sa); return 0; } 

Et voici la sortie:

faire de l’événement
terminé

faire de l’événement
..observé!
terminé

faire de l’événement
terminé

faire de l’événement
..observé!
..observé!
terminé
faire de l’événement
..observé!
terminé

La FAQ # 1 dans la documentation de la fonction boost semble répondre à votre question – et la réponse simple est “non”.

La proposition (section IIIb.) Précise qu’elles ne seront en aucun cas comparables. Si vous leur attachez des informations supplémentaires, vous pouvez facilement identifier chaque rappel. Par exemple, si vous définissez simplement une structure englobant le pointeur de fonction, vous pouvez les supprimer (en supposant que vous ayez la même structure que vous avez insérée). Vous pouvez également append des champs à la structure (comme un guide généré automatiquement par le client) et le comparer.

Si vous ne stockez que les pointeurs de fonction (et pas les autres foncteurs correspondant à la signature requirejse), cela est facile (voir le code ci-dessous). Mais en général, la réponse, comme l’ont dit d’autres afficheurs, est non. Dans ce cas, vous souhaiterez probablement stocker vos foncteurs dans un hachage, en tant que valeurs, avec les clés fournies par l’utilisateur lors de l’ajout et de la suppression.

Le code ci-dessous montre comment obtenir l’object foncteur / pointeur à appeler. Pour l’utiliser, vous devez connaître le type exact de l’object à extraire (c’est-à-dire que l’ typeid du type que vous spécifiez doit correspondre à l’ typeid du type du foncteur / pointeur contenu).

 #include  #include  using std::printf; using std::tr1::function; int main(int, char**); static function main_func(&main); int main(int argc, char** argv) { printf("%p == %p\n", *main_func.target(), &main); return 0; } 

Qu’en est-il de

 map > listeners; 

J’ai eu un problème similaire et j’ai trouvé une solution. J’ai utilisé certaines fonctionnalités C ++ 0x, mais uniquement pour des raisons de commodité, elles ne constituent pas une partie essentielle. Jetez un coup d’oeil ici:
> Système de messagerie: les rappels peuvent être n’importe quoi