2012-03-31 14 views
16

Non posso dire dallo standard C++ 11 se nullptr_t ha un costruttore predefinito. In altre parole, è la seguente valida ?:È nullptr_t un tipo costruibile di default?

nullptr_t n; 

GCC e VC++ consentono al codice di cui sopra, ma clang non lo fa. Non riesco a trovare nulla nello Standard specificando che non ha un costruttore predefinito, e quello che posso trovare suggerisce che dovrebbe. Questo è importante per me perché sto scrivendo un'implementazione di fallback di base di nullptr per il supporto del compilatore più vecchio e ho bisogno di sapere se devo dargli un costruttore predefinito.

+0

Ho pensato che dovevi gestire un 'nullptr_t' come un semplice tipo di puntatore, cioè non come una classe. Quindi sto assumendo 'nullptr_t n;' crea una variabile _uninitialised_; dovresti scrivere in modo esplicito 'nullptr_t n = nullptr;' Ma non ho un compilatore C++ 11 qui, quindi non posso controllare. E non riesco a trovare dove lo leggo nelle specifiche formali ... –

+0

FWIW, clang accetta "nullptr_t n;" Qui. –

risposta

17

Che cosa dice la standard

La norma dice (18,2)

nullptr_t è definito come segue:

namespace std { 
    typedef decltype(nullptr) nullptr_t; 
} 

tipo per il quale nullptr_t è sinonimo ha le caratteristiche descritte nel 3.9.1 e 4.10.

Dove 3.9.1 fondamentalmente dice che dovrebbe essere della stessa dimensione e void* 4.10 specifica le regole di conversione per nullptr.

Edit: 3.9.9 afferma inoltre esplicitamente che nullptr_t è un tipo scalare, il che significa che le regole di inizializzazione previsti per tipi built-in da 8.5 applica:

  • Default-inizializzazione (nullptr_t n;), che lascia il valore di n indefinito. Come ha indicato correttamente Johannes Schaub, questo si integra bene con la versione più recente di Clang.
  • valore di inizializzazione (nullptr_t n = nullptr_t();), che inizializza n a 0.

Questo comportamento è identico a es int, quindi nullptr_t è decisamente predefinito-constructible. La domanda interessante qui è: cosa significa per nullptr_t avere un valore non definito? Alla fine della giornata, c'è un solo valore significativo possibile per nullptr_t, che è nullptr. Inoltre, il tipo stesso è definito solo attraverso la semantica del valore letterale nullptr. Queste semantiche si applicano ancora per un valore unitario?

Perché questa domanda non ha importanza nella pratica

Non si vuole dichiarare una nuova variabile di tipo nullptr_t. L'unica semantica significativa di quel tipo è già espressa attraverso il valore letterale nullptr, quindi ogni volta che useresti la tua variabile personalizzata di tipo nullptr_t, puoi anche usare nullptr.

Ciò che conta, in pratica

L'unica eccezione a questo deriva dal fatto che si può prendere non di tipo parametri di modello di tipo nullptr_t. In questo caso, è utile sapere quali valori possono essere convertiti in nullptr_t, che è descritto in 4.10:

Un puntatore nullo costante è un'espressione costante intera (5.19) prvalue di tipo intero che restituisce zero o un prvalue di tipo std::nullptr_t. [...] Una costante puntatore nullo di tipo integrale può essere convertita in un valore di tipo std::nullptr_t.

Che sostanzialmente fa proprio quello che ci si aspetta: È possibile scrivere

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

ma non

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

Sia gcc 4.6 e Clang SVN ottenere questo diritto.

+1

Stai commettendo l'errore di generalizzare qualcosa che è vero per le classi alle non classi. Le non classi non hanno alcuna funzione membro. –

+1

I tipi non di classe possono essere costruttibili in modo predefinito senza avere una funzione membro. Non si tratta di avere un costruttore predefinito nel senso di avere una funzione membro, ma nel senso di soddisfare il concetto di un tipo costruibile di default. – ComicSansMS

+0

Dallo standard: "Il tipo per il quale nullptr_t è un sinonimo ha le caratteristiche descritte in 3.9.1 e 4.10." Visita la sezione 3.9.1 (Tipi fondamentali) e impara che puoi dichiarare variabili immesse da tip, float-typed, anzi, nullptr_t-typed. –

1

Mentre nullptr è una nuova aggiunta al linguaggio stesso, std::nullptr_t è solo un alias di un tipo senza nome, l'alias dichiarato cstddef come questo:

typedef decltype(nullptr) nullptr_t; 

Mentre nullptr_t, essendo un typedef e non una lingua parola chiave, non è elencato come un tipo fondamentale, si specifica che si comporta come un tipo fondamentale (e non, ad esempio, come un tipo di puntatore o un tipo di classe). Pertanto non ha un costruttore predefinito, ma puoi comunque dichiarare una variabile come hai fatto tu. La tua variabile non è inizializzata e mi chiedo quale sia il suo utilizzo e quale messaggio di errore hai ottenuto esattamente da clang.

Vedere anche here.

+0

Penso che la spec parlando dei valori di nullptr_t nella sezione "Tipi fondamentali" implichi che nullptr_t sia un tipo fondamentale. Non esiste un elenco esplicito di tipi di tipi fondamentali, il che significa che bisogna riunirli iterando su tutti i tipi menzionati in "Tipi fondamentali". E ha molto senso che è comunque un tipo fondamentale. –

+4

Nota che non puoi pronunciare "Tipo nullptr_t è un typedef di libreria". Un typedef * non * introduce un nuovo tipo. Crea semplicemente un alias su un tipo esistente. Il tipo che "alias * nullptr_t" è * introdotto dalla lingua. –

+0

@ JohannesSchaub-litb - OK, modificato la domanda per chiarire questo punto. Questo punto è, il tipo di "nullptr" non ha alcun nome o alias in un programma C++ fino a quando non viene assegnato un alias (operazione migliore utilizzando il file di intestazione della libreria standard). –

Problemi correlati