43 Stimmen

Wie kann man einen Funktionszeiger übergeben, der auf einen Konstruktor zeigt?

Ich arbeite an der Implementierung eines Reflexionsmechanismus in C++. Alle Objekte in meinem Code sind eine Unterklasse von Object (mein eigener generischer Typ), die ein statisches Mitgliedsdatenelement vom Typ Class enthalten.

class Class{
public:
   Class(const std::string &n, Object *(*c)());
protected:
   std::string name;     // Name for subclass
   Object *(*create)();  // Pointer to creation function for subclass
};

Für jede Unterklasse von Object mit einem statischen Class-Member-Datum möchte ich in der Lage sein, 'create' mit einem Zeiger auf den Konstruktor dieser Unterklasse zu initialisieren.

0 Stimmen

Auch wenn dies erst 6 Jahre später geschieht - Sie sollten sich gut überlegen, ob Sie wirklich Ihre eigene Reflexionsmechanik einführen wollen. Überlegen Sie zunächst, ob Sie sich mit der Kompilierzeit-"Reflexion" unter Verwendung von Templates, type_traits und dem SFINAE-Prinzip zufrieden geben wollen; dann probieren Sie eine der vorhandenen C++-Reflection-Bibliotheken aus; und erst dann würde ich in Erwägung ziehen, es selbst zu versuchen.

70voto

Michael Burr Punkte 320591

Die Adresse eines Konstruktors kann nicht übernommen werden (C++98 Standard 12.1/12 Konstruktoren - "12.1-12 Konstruktoren - "Die Adresse eines Konstruktors darf nicht übernommen werden.")

Am besten ist es, wenn Sie eine Fabrikfunktion/Methode haben, die die Object und geben Sie die Adresse der Fabrik an:

class Object;

class Class{
public:
   Class(const std::string &n, Object *(*c)()) : name(n), create(c) {};
protected:
   std::string name;     // Name for subclass
   Object *(*create)();  // Pointer to creation function for subclass
};

class Object {};

Object* ObjectFactory()
{
    return new Object;
}

int main(int argc, char**argv)
{
    Class foo( "myFoo", ObjectFactory);

    return 0;
}

7 Stimmen

Wenn man es zu einer Vorlage macht, wird es tatsächlich "Klasse" zurückgeben: template<typename T> Object* ObjectFactory() { return new T; } .... Klasse foo("myFoo", &ObjectFactory<Class>);

0 Stimmen

8voto

Andrew Wansink Punkte 81

Ich bin auf das gleiche Problem gestoßen. Meine Lösung war eine Vorlagenfunktion, die den Konstruktor aufrief.

template<class T> MyClass* create()
{
    return new T;
}

Die Verwendung als Funktionszeiger ist einfach:

MyClass* (*createMyClass)(void) = create<MyClass>;

Und um eine Instanz von MyClass zu erhalten:

MyClass* myClass = createMyClass();

6voto

kungfooman Punkte 3915

Lambda-Stil:

[](){return new YourClass();}

2 Stimmen

Bitte fügen Sie weitere Erklärungen/Kontexte hinzu, damit die Antwort für künftige Leser nützlicher ist.

1 Stimmen

Erwähnen Sie auf jeden Fall, dass dies eine Funktion von C++11 und höher ist.

0 Stimmen

Können Sie die ()

4voto

bradgonesurfing Punkte 29536

Mit variadischen Vorlagen können Sie einen Wrapper erstellen, der den Konstruktor in einen Funktor verwandelt.

#include <utility>

template <typename T>
struct BindConstructor{
    template<typename... Args>
    T operator()(Args&&...args)const{
        return T(std::forward<Args>(args)...);
    }
};

struct Foo {
    Foo(int a, int b):a(a),b(b){}
    int a;
    int b;
};

template <typename Fn>
auto Bar(Fn f){
    return f(10,20);
}

int main(){
    Foo foo = Bar(BindConstructor<Foo>());
}

https://godbolt.org/z/5W383McTc

1 Stimmen

Du hast vergessen && über die operator() Argument(e).

0 Stimmen

Ich danke Ihnen. Behoben

3voto

laalto Punkte 143902

Hmm, seltsam. create ist eine Mitgliedsvariable, d.h. sie ist nur in Klasseninstanzen verfügbar, aber die Absicht scheint zu sein, überhaupt eine Instanz zu erstellen.

Sie können die Adresse eines Konstruktors nicht übernehmen, aber Sie können eigene statische Fabrikmethoden erstellen und die Adresse dieser Methoden übernehmen.

1 Stimmen

Laalto, Wenn ich das Klassenobjekt konstruiere, gebe ich einen Namen und eine Erstellungsfunktion an. Mein Ziel ist es, eine Liste von Klassen zu haben, auf die ich überall in meinem Projekt verweisen kann. Ein Zeiger auf eine statische Mitgliedsfunktion würde funktionieren.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X