2015-04-30 13 views
7

Ich glaube, moderne C++ initializer Listen zur Initialisierung Objekten sehr nützlich sind, bis zu dem Punkt wodurch die Notwendigkeit für Ihren eigenen Konstruktor definieren:aktiviert Standard Initialisiererliste Konstruktor

struct point 
{ 
    float coord[3]; 
}; 

point p = {1.f, 2.f, 3.f}; // nice ! 

Dies ist jedoch nicht funktioniert, wenn mein Klasse erbt von einer anderen Klasse:

template<typename T> 
class serializable 
{ 
    protected: 
     serializable() = default; 
    ... 
    // other stuff 
} 

struct point : public serializable<point> 
{ 
    float coord[3]; 
}; 
point p = {1.f, 2.f, 3.f}; // Doesn't work :(

ich versuchte point() = default; zu meinem Punkt Klasse hinzufügen, aber das hat nicht funktioniert entweder. Wie kann ich den Punkt mit einer Initialisierungsliste initialisieren?

Antwort

8

Ihr ursprünglicher Fall stützte sich auf Aggregate Initialisierung [dcl.init.list]:

List-Initialisierung eines Objekt oder eine Referenz vom Typ T wird wie folgt definiert:
...
- Sonst wenn T ein Aggregat ist, wird Aggregat Initialisierung

ausgeführt

Wo ein Aggregat und Aggregat initialiazation sind, von [dcl.init.aggr], Hervorhebung von mir:

ein Aggregat ist, ein Array oder eine Klasse (Abschnitt 9) ohne Benutzer bereitgestellten Konstruktoren (12.1), keine privaten oder geschützte nicht statische Datenelemente (Ziffer 11), keine Basisklassen (Ziffer 10), und keine virtuellen Funktionen (10.3).

Wenn ein Aggregat von einer Initialisierungsliste initialisiert wird, wie in 8.5.4 angegeben, werden die Elemente der Initialisierungsliste als Initialisierer für die Mitglieder des Aggregats in aufsteigender Subskription oder Mitgliederreihenfolge verwendet. Jedes Member wird aus der entsprechenden Initialisierungsklausel initialisiert.

Aber jetzt, da point eine Basisklasse (serializable<point>) hat, ist point nicht ein Aggregat mehr und nicht mehr unterstützt Aggregat Initialisierung.

Die Lösung ist einfach, eine solche Konstruktor zur Verfügung zu stellen point initialisieren:

struct point : public serializable<point> 
{ 
    template <typename... T> 
    point(T... ts) 
    : coord{ts...} 
    { } 

    float coord[3]; 
}; 
+0

danken, dass Sie klare und ausführliche Antwort. Diese Frage lässt mich fragen, warum der Standart so ist. Ich nehme an, es ist, weil Konstruktor s sonst nicht aufgerufen würde ... und vielleicht in einigen Fällen könnten sie Conflits zwischen den Konstruktoren und der Listeninitialisierung sein. Wie auch immer, da alle Konstruktoren '= default' sind, sollte das kein Problem verursachen. – Amxx

+0

@Amxx Was wäre, wenn die Basisklassen Mitglieder hätten? Was wäre, wenn diese Mitglieder standardmäßig konstruierbar wären? Es ist unklar, was das "Richtige" in all diesen Fällen zu tun hat - so entscheidet sich der Standard, nicht zu raten. – Barry

+0

Sie können Ihre Daten auch in eine Member- oder Basisklasse stopfen, wie zum Beispiel 'struct point_data {float coord [3]; } ', dann habe einen" perfekten Weiterleitungskonstruktor ", der' {} 'basierte Konstruktion davon macht. – Yakk