2012-03-31 4 views
16

Ich kann nicht aus dem C++ 11 Standard erkennen, wenn nullptr_t einen Standardkonstruktor hat. Mit anderen Worten, ist die folgende gültig ?:Ist nullptr_t ein Standard-Konstruktyp?

nullptr_t n; 

GCC und VC++ dem obigen Code erlauben, aber Klappern nicht. Ich kann im Standard nichts finden, das angibt, dass es keinen Standardkonstruktor hat, und was ich finden kann, legt nahe, dass es das tun sollte. Das ist mir wichtig, weil ich eine grundlegende Fallback-Implementierung von nullptr für ältere Compiler-Unterstützung schreibe und wissen muss, ob ich ihm einen Standardkonstruktor geben muss.

+0

Ich dachte, Sie sollten mit einem 'nullptr_t' als einfacher Zeigertyp umgehen, d. H. Nicht als Klasse. Ich nehme an, dass "nullptr_t n;" eine _uninitialized_ Variable erstellt; Sie sollten 'nullptr_t n = nullptr;' explizit schreiben. Aber ich habe hier keinen C++ 11-Compiler, deshalb kann ich das nicht überprüfen. Und ich kann nicht finden, wo ich es in den formalen Spezifikationen lese ... –

+0

FWIW akzeptiert clang "nullptr_t n;" Hier. –

Antwort

17

Was die Norm sagt

Der Standard sagt (18,2)

nullptr_t ist wie folgt definiert:

namespace std { 
    typedef decltype(nullptr) nullptr_t; 
} 

Die Art, für die nullptr_t ein Synonym ist, hat die beschriebenen Merkmale in 3.9.1 und 4.10.

Wo 3.9.1 im Grunde sagt, dass es die gleiche Größe wie void* und 4,10 sein sollte, legt die Konvertierungsregeln für nullptr.

Edit: 3.9.9 ferner ausdrücklich darauf hin, dass nullptr_t ein Skalar-Typ, der für die erwartete Initialisierung Regeln bedeutet eingebaute Typen von 8,5 gelten:

  • Standard-Initialisierung (nullptr_t n;), das hinterlässt den Wert n undefined. Wie Johannes Schaub richtig ausgeführt hat, ist dies mit der neuesten Version von Clang gelungen.
  • Wert-Initialisierung (nullptr_t n = nullptr_t();), die n auf 0.

Dieses Verhalten ist identisch mit initialisiert z.B. int, also nullptr_t ist definitiv standardmäßig konstruierbar. Die interessante Frage hier ist: Was bedeutet es für nullptr_t, einen undefinierten Wert zu haben? Am Ende des Tages gibt es nur einen sinnvollen möglichen Wert für nullptr_t, der nullptr ist. Außerdem ist der Typ selbst nur durch die Semantik des nullptr Literals definiert. Gilt diese Semantik noch für einen unitären Wert?

Warum diese Frage keine Rolle spielt in der Praxis

Sie wollen nicht nullptr_t eine neue Variable vom Typ deklarieren. Die einzige sinnvolle Semantik dieses Typs wird bereits durch das nullptr Literal ausgedrückt. Wenn Sie also Ihre benutzerdefinierte Variable vom Typ nullptr_t verwenden, können Sie genauso gut nullptr verwenden.

Was in der Praxis nicht egal

Die einzige Ausnahme davon kommt von der Tatsache, dass Sie nicht-Typ Template-Parameter vom Typ nullptr_t nehmen. Für diesen Fall ist es nützlich zu wissen, welche Werte in nullptr_t konvertiert werden können, was in 4 beschrieben ist.10:

Ein Nullzeiger Konstante ist ein integraler konstanter Ausdruck (5.19) prvalue ganzzahliger Typ, der std::nullptr_t auf Null oder einem prvalue vom Typ auswertet. [...] Eine Null-Zeiger-Konstante vom Integraltyp kann in einen Pr-Wert vom Typ std::nullptr_t konvertiert werden.

, die im Grunde nur das tut, was man erwarten würde: Sie

nullptr_t n = 0; // correct: 0 is special 

schreiben kann, aber nicht

nullptr_t n = 42; // WRONG can't convert int to nullptr_t 

Beide gcc 4.6 und Clang SVN dieses Recht bekommen.

+1

Sie machen den Fehler, etwas, das für Klassen gilt, auf Nicht-Klassen zu verallgemeinern. Nicht-Klassen haben überhaupt keine Mitgliedsfunktionen. –

+1

Nicht-Klassen-Typen können default-constructible ohne eine Member-Funktion sein. Es geht nicht darum, einen Standardkonstruktor in dem Sinne zu haben, eine Memberfunktion zu haben, sondern in dem Sinne, dass das Konzept eines Default-Constructible-Typs erfüllt wird. – ComicSansMS

+0

Aus dem Standard: "Der Typ, für den nullptr_t ein Synonym ist, hat die in 3.9.1 und 4.10 beschriebenen Eigenschaften." Besuchen Sie Abschnitt 3.9.1 (Grundlegende Typen) und erfahren Sie, dass Sie int-typisierte, float-typed, in der Tat nullptr_t-typed-Variablen deklarieren können. –

1

Während nullptr eine neue Ergänzung zu der Sprache selbst ist, std::nullptr_t ist nur ein Alias ​​eines ungenannten Typ, erklärte der Alias ​​in cstddef wie folgt aus:

typedef decltype(nullptr) nullptr_t; 

Während nullptr_t, ein typedef sein und keine Sprache Schlüsselwort, ist nicht als ein grundlegender Typ aufgeführt, es ist angegeben, sich als grundlegender Typ zu verhalten (und nicht zum Beispiel als Zeigertyp oder Klassentyp). Daher hat es keinen Standardkonstruktor, aber Sie können trotzdem eine Variable deklarieren, wie Sie es getan haben. Ihre Variable ist nicht initialisiert und ich frage mich, was sie verwenden könnte und welche Fehlermeldung Sie genau von clang erhalten haben.

Siehe auch here.

+0

Ich denke, die Spezifikation, die über Werte von nullptr_t im Abschnitt "Grundtypen" spricht, impliziert, dass nullptr_t ein grundlegender Typ ist. Es gibt keine explizite Liste, welche Typen grundlegende Typen sind, was bedeutet, dass man sie durch Iterieren über alle in "Grundtypen" erwähnten Typen sammeln muss. Und es macht sehr viel Sinn, dass es sowieso ein grundlegender Typ ist. –

+4

Beachten Sie, dass Sie nicht sagen können "Typ nullptr_t ist eine Bibliothek typedef". Ein typedef führt * nicht * einen neuen Typ ein. Es erstellt einfach einen Alias ​​für einen vorhandenen Typ. Der Typ, der "nullptr_t" Aliase * ist, wird von der Sprache eingeführt *. –

+0

@ JohannesSchaub-litb - OK, habe die Frage bearbeitet, um diesen Punkt klarer zu machen. Dieser Punkt ist, der Typ von "nullptr" hat keinen Namen oder Alias ​​in einem C++ - Programm, bis ein Alias ​​zugewiesen ist (am besten mit der Header-Datei der Standardbibliothek). –