2009-01-23 15 views
6

Ich arbeite an einer Ressourcenverwaltungsklasse und möchte, dass der Benutzer einer "ReleaseResource" -Methode als Teil des Konstruktors des Ressourcenmanagers einen Funktor zur Verfügung stellt. Von dort, wenn eine Ressource angefordert wird, wird Funktor als Deleter für die shared_ptr bereitgestellt, die ich zurückgeben werde, so dass die entsprechende Methode aufgerufen wird, wenn die Ressource nicht mehr verwendet wird.Funktoren als Variablen beibehalten

Das Problem, auf das ich stoße, das erfordert mich, den Funktor in meiner Klasse zu speichern, und ich bin nicht ganz sicher, wie man das macht. Normalerweise, wenn ein Funktor mit Vorlage Sie die Funktion wie folgt:

template<class MyFunctor> MyMethod(MyFunctor f) { 
    f(); 
} 

Das ist sehr gut, wenn Sie den Funktors in dem Anwendungsbereich dieser Funktion verwenden wollen, aber da die Vorlage geht aus Rahmen mit der Funktion Ich bin nicht sicher, wie Sie eine Variable des passenden Typs angeben würden, um den Funktor zur späteren Verwendung zu speichern.

Kann mir hier jemand in die richtige Richtung zeigen?

Antwort

8
template<class MyFunctor> MyMethod(MyFunctor f) { 
    boost::function<void()> g = f; 
    g(); 
} 

Der Typ, den Sie an boost::function übergeben, ist der Funktionstyp. Zum Beispiel ist int(bool, char) der Typ einer Funktion, die int zurückgibt und ein bool und ein char annimmt. Das heißt, wenn Sie das shared_ptr sofort erstellen möchten, müssen Sie den Funktor nicht irgendwo speichern (boost::function erfordert den Operator new dafür, obwohl für sehr kleine Funktoren spezielle Tricks verwendet werden, um nur die Stapelzuweisung zu verwenden (kleine Pufferoptimierung)):

template<class MyFunctor> MyMethod(MyFunctor f) { 
    boost::shared_ptr<T> ptr(new T, f); 
} 

boost :: function Teil tr1 ist und wird Teil der nächsten offiziellen C++ Standard sein. Beispiel:

struct Manager { 
    template<typename Deleter> 
    Manager(Deleter d) 
     :deleter(d) { 

    } 

    boost::shared_ptr<Resource> allocate() { 
     ... 
     return boost::shared_ptr<Resource>(resource, deleter); 
    } 

private: 
    boost::function<void(Resource *)> deleter; 
}; 
+0

Ausgezeichnet! Genau das habe ich gesucht. Vielen Dank! – Toji

0

Nicht sicher, ob dies helfen würde, aber bedenken Sie, dass boost :: shared_ptr Konstruktorüberschreibungen hat, die es dem Benutzer erlauben, eine benutzerdefinierte Aufhebung der Zuweisung (und benutzerdefinierten Zuordner, falls gewünscht) einzuschließen. Dies könnte ausreichend sein für das, was Sie benötigen (es wurde so konzipiert, dass ich Ihren Anwendungsfall richtig lese).

+0

Ich bin mir dessen bereits bewusst und verwende es im obigen Beispiel. Was ich wissen muss, ist wie man den übergebenen Parameter speichert. – Toji

3

Es gibt zwei Möglichkeiten, von denen beide biologisieren, um die Klasse zu templatieren.

template <MyFunctor> 
class MyClass 
{ 
    MyFunctor func; 
    public: 
    MyClass(MyFunctor f) :func(f) 
    { } 


    MyMethod() 
    { 
     func(); 
    } 
} 

Dies würde erfordern, dass Sie den Typ des Funktors kennen. Um zu vermeiden, dass, können wir eine Fabrik verwenden:

template<MyFunctor> 
MyClass<MyFunctor> MakeFunctorClass(MyFunctor f) 
{  
    return MyClass<MyFunctor>(f);  
} 

Alternativ, da aller Wahrscheinlichkeit nach die meisten der Funktors Signatur wird die gleiche sein, mit nur einem kleinen Teil wechselnden, könnten wir das verwenden:

template <MyType> 
class MyClass 
{ 
    typedef std::binary_function<MyType, MyType, bool> MyFunctor; 
    MyFunctor func; 
    public: 


    MyMethod(MyFunctor f) 
    { 
     func = f; 
     func(); 
    } 
} 

Dies macht Nutzung ein bisschen einfacher:

bool AreEqual(int, int); 
MyClass<int> myc; 
myc.MyMethod(AreEqual); 

am teuren einer trickier Definition (dh ich nicht garantieren, dass die binary_function typedef ich werde arbeiten gab)

+0

Mit Ausnahme, dass 'binary_function' nicht funktioniert. binary_function ist ein type-trait-giving-Attribut, keine Schnittstelle.Es hat keinen Apply-Operator, daher ist die Anweisung 'func()' ungültig, auch wenn Sie Argumente angeben. siehe andere Antwort in Bezug auf boost :: function oder tr1 :: function. – Aaron

+0

Deshalb habe ich ausdrücklich gesagt: "Ich garantiere nicht, dass die binary_function typedef, die ich angegeben habe, funktioniert". Ich war mir ziemlich sicher, dass das nicht der Fall war, aber ich wusste, dass es einen Standardtyp gab, der das würde. –