2014-10-13 5 views
5

Ok, das ist kompliziert.Code einmal für jede C++ Klassenschabloneninstanz ausführen

Ich habe eine C++ - Klassenvorlage, die viele Male instanziiert wird. Für jede dieser Instanzen muss ich eine Funktion ausführen, die einige Operatoren registriert. Dies muss nur einmal pro Vorlageninstanz geschehen, bevor das erste Objekt dieser Vorlageninstanz verwendet wird (was nicht bedeutet, dass es unter Instanziierung ausgeführt werden muss, was während der Kompilierzeit geschieht).

Bis heute habe ich das manuell gemacht. Aber es ist ein Schmerz. Also möchte ich die Registrierungsfunktion automatisch ausführen.

Meine aktuelle Idee ist es, eine geschützte Registrierungsmethode im Konstruktor aufzurufen. Dies erfordert jedoch einen (geringen) Overhead, wenn eine Instanz der Klasse aufgebaut wird. Da dies sehr oft gemacht wird, möchte ich diesen Overhead vermeiden.

Ich habe auch versucht, ein statisches RAII-Helferelement zu verwenden, aber statische Vorlagenklassenelemente werden nicht erstellt, wenn sie nicht aktiv zugegriffen werden, so dass dieser Versuch fehlgeschlagen ist.

Gibt es eine Möglichkeit, Code auf Klassenschabloneninstanz (von einer Funktion oder vielleicht von einer RAII-Helferklasse) ohne Laufzeitaufwand auszuführen?

+0

Normalerweise Vorlagen bei der Kompilierung zur Laufzeit nicht instanziiert werden. Sind Sie sicher, Ihr Problem ist real? – BitTickler

+0

Ja ist es. Ich muss den Code * bei * Instanziierung nicht ausführen. Ich muss es vor der ersten Verwendung eines Objekts ausführen. – Silicomancer

Antwort

6

Sie können ein statisches Datenelement hinzufügen, das alle erforderlichen Funktionen in Konstruktor und Destruktor ausführt. Sie können seine Definition sicher in eine Header-Datei schreiben, denn solange sie eine Vorlage ist, wird sie nur einmal definiert. Der einzige Haken ist, dass Sie es instanziieren müssen odr-use es.

template <typename T> 
class Data { 
public: 
    Data() { 
     std::cout << "creating Data<" << typeid(T).name() << '>' << std::endl; 
    } 
    ~Data() { 
     std::cout << "destroying Data<" << typeid(T).name() << '>' << std::endl; 
    } 
}; 

template<typename T> 
class A { 
    static Data<T> data; 
public: 
    A() { 
     // this is necessary for data to be instantiated 
     (void)data; 
    } 
}; 

// This also should be in a header 
template<typename T> 
Data<T> A<T>::data; 

int main(){ 
    A<int> aInt; 
    A<int> aInt2; 
    A<float> aFloat; 
} 

Demo

EDIT: Das ist eigentlich ein bisschen unsicher, da die Reihenfolge der Erstellung von statischen Objekten in verschiedenen Übersetzungseinheiten nicht spezifiziert ist, so zum Beispiel keine std::cout von Data::Data() im Moment der exetucion sein kann (Verwenden Sie also dort keine statischen globalen Objekte). Ein sicherer Ansatz ist eine statische Funktion in A::A() zu nennen, obwohl es einigen Aufwand führt:

template<typename T> 
class A { 
    static void createData() { 
     static Data<T> data; 
    } 
public: 
    A() { 
     createData(); 
    } 
}; 
+0

Großartig! Diese Lösung funktioniert für mich! Eigentlich habe ich etwas * sehr * ähnliches versucht aber es hat nicht funktioniert weil ich die "Vorlage Daten A :: data;" Linie. Sollte ich nicht einen Fehler bekommen, wenn ich vergesse, diese Zeile hinzuzufügen? – Silicomancer

+0

Ah, noch eine ... warum "(leere) Daten;" anstelle von "Daten"? – Silicomancer

+1

@Silicomancer einfach 'data;' ergibt eine Compiler-Warnung "Anweisung hat keine Wirkung". –