2011-01-03 15 views
11

Say desea almacenar la siguiente:vector de std :: función <>

typedef std::function<void(int)> MyFunctionDecl; 

..en una colección:

typedef std::vector<MyFunctionDecl> FunctionVector; 
FunctionVector v; 

Esto es posible, pero si quiero encontrar algo con std::find:

FunctionVector::const_iterator cit = std::find(v.begin(), v.end(), myFunctionDecl); 

.. obtenemos un error debido a que el operador ==.

Como se ha sugerido a mí en una pregunta anterior en relación con esto, esto se puede conseguir en torno al encapsular la declaración de función dentro de otra clase, que ofrece un operador de ==:

class Wrapper 
{ 
private: 
    MyFunctionDecl m_Func; 

public: 
    // ctor omitted for brevity 

    bool operator == (const Wrapper& _rhs) 
    { 
     // are they equal? 
    }; // eo == 
}; // eo class Wrapper 

Así que lo que quiero hacer de alguna manera genera un hash para "MyFunctionDecl" para que pueda implementar correctamente el operador ==. Podría tener algún tipo de identificador único y pedirle a la persona que llama que proporcione un identificador único para el delegado, pero parece un poco molesto y propenso a errores.

¿Hay alguna manera de que pueda hacer esto? ¿Para que las mismas funciones devuelvan la misma ID con fines comparativos? Hasta ahora, la única forma de evitarlo es eliminar la noción de usar std::function y volver a usar delegados rápidos que admiten comparaciones. Pero luego pierdo la habilidad de usar lambdas.

¡Cualquier ayuda apreciada!

EDITAR

dado la respuesta más adelante, esto es lo que he llegado con ... cualquier advertencia que podría haber perdido? Estoy en el proceso de ponerlo a su propio ritmo ahora:

class MORSE_API Event : boost::noncopyable 
{ 
public: 
    typedef std::function<void(const EventArgs&)> DelegateType; 
    typedef boost::shared_ptr<DelegateType> DelegateDecl; 

private: 
    typedef std::set<DelegateDecl> DelegateSet; 
    typedef DelegateSet::const_iterator DelegateSet_cit; 
    DelegateSet m_Delegates; 

public: 
    Event() 
    { 
    }; // eo ctor 


    Event(Event&& _rhs) : m_Delegates(std::move(_rhs.m_Delegates)) 
    { 
    }; // eo mtor 

    ~Event() 
    { 
    }; // eo dtor 

    // methods 
    void invoke(const EventArgs& _args) 
    { 
     std::for_each(m_Delegates.begin(), 
         m_Delegates.end(), 
         [&_args](const DelegateDecl& _decl) { (*_decl)(_args); }); 
    }; // eo invoke 

    DelegateDecl addListener(DelegateType f) 
    { 
     DelegateDecl ret(new DelegateType(f)); 
     m_Delegates.insert(ret); 
     return ret; 
    }; // eo addListener 

    void removeListener(const DelegateDecl _decl) 
    { 
     DelegateSet_cit cit(m_Delegates.find(_decl)); 
     if(cit != m_Delegates.end()) 
      m_Delegates.erase(cit); 
    }; // eo removeListener 

}; // eo class Event 
+1

¿Por qué necesita encontrarlo?Si necesita encontrar una función std :: como esta, deberá encontrarla en función de algún identificador o similar, por ejemplo, una int generada automáticamente para cada nuevo Wrapper que cree. Obtenga la int para una comparación futura y asegúrese de crear solo cada contenedor una vez. – villintehaspam

+0

No se pueden comparar funciones, este es el * problema de detención * (http://en.wikipedia.org/wiki/Halting_problem) –

+2

@Alexandre Creo que el problema de la detención está relacionado, pero definitivamente no es el mismo. Creo que la idea del hash es que no necesitas ejecutar la función para compararlo. –

Respuesta

6

¿Has mirado en Boost Signals? Es posible que ya esté haciendo lo que quiere hacer.

De todos modos, una forma simple de ajustar el function sería usar un shared_ptr. Si lo hace

typedef std::shared_ptr<std::function<void(int)> > MyFunctionDecl; 

y asegúrese de que la función se envuelve inmediatamente dentro de la shared_ptr cuando se crea (de modo que el puntero es única), los punteros pueden ser probados por la igualdad por lo std::find funcionaría.

Por ejemplo, usted puede hacerlo con una función de fábrica como

template <class Functor> 
MyFunctionDecl createDelegate(Functor f) { 
    return MyFunctionDecl(new std::function<void(int)>(f)); 
} 

De esta manera se da una identidad única para la función (el puntero) cuando se crea el delegado.

Por cierto, que haría uso de un std::set en lugar de un std::vector, ya que ambos son find y erase logarítmica en lugar de lineal.

+0

gracias por esto. He creado una implementación dada su idea y estoy en proceso de verificarla ahora. He modificado mi publicación original para mostrar el código actual. ¡Gracias! –

-1
#include <boost/type_traits.hpp> 
#include <iostream> 

template<typename T> 
class Wrapper 
{ 
    private: 
     T m_Func; 

    public: 

     template<typename U> 
     bool operator==(const Wrapper<U>& _rhs) 
     { 
      return boost::is_same<T, U>::value; 
     } 
}; 

int main() 
{ 
    Wrapper<int> Wint; 
    Wrapper<bool> Wbool; 
    std::cout << (Wint == Wbool) << std::endl; 
    std::cout << (Wint == Wint) << std::endl; 
} 
+0

Esto realmente no resuelve el problema. boost :: is_same comprueba la igualdad de tipo, no la igualdad de objeto. – villintehaspam

+1

Pero Wrapper tiene un operador == –

+0

Sí, también lo hacen muchas otras clases que no ayudan ... :) – villintehaspam

Cuestiones relacionadas