2011-01-03 16 views
11

Say möchte folgendes speichern:Vector von std :: function <>

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

..in einer Sammlung:

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

Dies ist möglich, aber wenn ich willfinden etwas mit std::find:

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

.. wir bekommen einen Fehler aufgrund der == Betreiber.

Wie mir in einer früheren Frage nach dieser vorgeschlagen worden ist, kann diese um innerhalb einer anderen Klasse durch Einkapseln der Funktionsdeklaration werden erhalten, die einen == Operator bietet:

class Wrapper 
{ 
private: 
    MyFunctionDecl m_Func; 

public: 
    // ctor omitted for brevity 

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

Also, was ich tun möchte, erzeugt irgendwie einen Hash für "MyFunctionDecl", so dass ich den == Operator richtig implementieren kann. Ich könnte eine Art eindeutiger Bezeichner haben und den Anrufer bitten, eine eindeutige Kennung für den Beauftragten anzugeben, aber das scheint ein bisschen mühsam und fehleranfällig zu sein.

Gibt es eine Möglichkeit, dass ich das tun kann? Damit dieselben Funktionen die gleiche ID für Vergleichszwecke liefern? Bis jetzt ist der einzige Weg, um den Begriff der Verwendung von std::function zu verlassen und wieder schnell Delegaten verwenden, die Vergleiche unterstützen. Aber dann verliere ich die Fähigkeit, Lambdas zu verwenden.

Jede Hilfe wird geschätzt!

EDIT

die Antwort Da unten, das ist, was ich mit ... irgendwelchen Einschränkungen kommen habe ich verpasst haben könnte? Ich bin in den Prozess es durch sie die Schritte jetzt setzen:

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

Warum müssen Sie suchen?Wenn Sie eine std :: -Funktion wie diese finden müssen, müssen Sie sie anhand eines Bezeichners oder ähnlichem suchen, z. B. ein automatisch generiertes int für jeden neuen Wrapper, den Sie erstellen. Holen Sie sich den int für den zukünftigen Vergleich und stellen Sie sicher, dass Sie nur jeden Wrapper einmal erstellen. – villintehaspam

+0

Sie können keine Funktionen vergleichen, dies ist das * Halteproblem * (http://en.wikipedia.org/wiki/Halting_problem) –

+2

@Alexandre Ich denke, das Anhalten Problem ist verwandt, aber definitiv nicht das Gleiche. Ich würde denken, dass die Idee des Hash ist, dass Sie die Funktion nicht ausführen müssen, um es zu vergleichen. –

Antwort

6

Haben Sie bei Boost Signals geschaut? Es kann bereits tun, was Sie tun möchten.

Wie auch immer, eine einfache Möglichkeit, die function zu wickeln wäre eine shared_ptr zu verwenden. Wenn Sie

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

tun und stellen Sie sicher, dass die Funktion unmittelbar innerhalb der shared_ptr gewickelt ist, wenn Sie es schaffen (so dass der Zeiger eindeutig ist), können Zeiger auf Gleichheit getestet werden, so würde std::find arbeiten.

Zum Beispiel können Sie dies mit einer Fabrik Funktion wie

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

Auf diese Weise können Sie eine eindeutige Identität auf die Funktion (dessen Zeiger) geben, wenn Sie den Delegaten erstellen.

BTW, würde ich einen std::set anstelle eines std::vector verwenden, da beide find und erase logarithmisch sind eher als linear.

+0

danke dafür. Ich habe eine Implementierung basierend auf Ihrer Idee erstellt und bin gerade dabei, sie zu überprüfen. Habe meinen ursprünglichen Beitrag so geändert, dass der aktuelle Code angezeigt wird. Vielen Dank! –

-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

Das löst das Problem nicht wirklich. boost :: is_same prüft auf Typgleichheit, nicht auf Objektgleichheit. – villintehaspam

+1

Aber Wrapper hat einen Operator == –

+0

Ja, also tun viele andere Klassen, die auch nicht helfen ... :) – villintehaspam

Verwandte Themen