c++ function tr1

c++ - Comparando objetos std:: tr1:: function<>



(7)

De acuerdo, me tienes trabajando. La parte difícil es tratar de hacer coincidir el patrón de uso exacto de los eventos de C #. Si te saltas eso, hay formas MUCHO más sencillas de hacer lo que estás pidiendo. (Mi compañero de trabajo Jason usa un objeto Notificador por todas partes). De todos modos, aquí está el código increíblemente aburrido que hace lo que quiere. Desafortunadamente, no le permite pasar parámetros del sujeto al observador. Para hacer eso, necesitarías agregar aún más inteligencia.

#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; }

Y aquí está la salida:

haciendo evento
hecho

haciendo evento
..¡observado!
hecho

haciendo evento
hecho

haciendo evento
..¡observado!
..¡observado!
hecho
haciendo evento
..¡observado!
hecho

He intentado implementar un sistema de eventos tipo C # en C ++ con las plantillas de funciones tr1 usadas para almacenar una función que maneja el evento.

Creé un vector para que múltiples oyentes puedan unirse a este evento, es decir:

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

Me gustaría poder eliminar un controlador de la lista para detener a un oyente que recibe eventos.

Entonces, ¿cómo puedo encontrar la entrada en esta lista que corresponde a un oyente dado? ¿Puedo probar si un objeto ''función'' en la lista se refiere a una función particular?

¡Gracias!

EDITAR: Después de analizar el enfoque boost :: signal, parece que probablemente se implemente utilizando un sistema token como algunos de ustedes han sugerido. Aquí hay algo de información sobre esto . Un observador retiene un objeto "Conexión" cuando se conectan a un evento, y este objeto de conexión se usa para desconectar si es necesario. Por lo tanto, parece que si utilizas Boost o enrollas el tuyo con tr1, el principio básico es el mismo. es decir, será un poco torpe :)


La propuesta (sección IIIb) establece que no serán comparables de ninguna manera. Si les adjunta información adicional, puede identificar fácilmente cada devolución de llamada. Por ejemplo, si simplemente define una estructura que envuelve el puntero a la función, puede eliminarlos (suponiendo que tenga la misma estructura que usted insertó). También puede agregar algunos campos a la estructura (como una guía generada automáticamente a la que el cliente puede aferrarse) y compararla con eso.


No sé si está encerrado en std C ++ y tr1, pero si no lo está, parece que su problema podría evitarse por completo si acaba de utilizar algo como boost :: signal y boost :: bind para resolver su problema original - crear un sistema de eventos - en lugar de intentar rodar el suyo propio.


Qué pasa

map<key-type, function<void (int)> > listeners;


Si solo almacena punteros de función (y no otros funtores que coincidan con la firma requerida), esto es fácil (vea el código a continuación). Pero en general, la respuesta, como han dicho otros carteles, es no. En ese caso, es probable que desee almacenar sus funtores en un hash, como valores, con claves que el usuario proporciona al agregar y eliminar.

El siguiente código muestra cómo obtener el objeto del puntero / funcionador que se llamará. Para usarlo, debe conocer el tipo exacto de objeto a extraer (es decir, el typeid del tipo que especifique debe coincidir con el typeid de typeid del funtor / puntero contenido).

#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; }