Restituire un vuoto?

Non capisco perché questo codice venga compilato senza errori:

#include  template  struct Test { static constexpr T f() {return T();} }; int main() { Test test; test.f(); // Why not an error? return 0; } 

Va bene secondo lo standard, o è una tolleranza del compilatore?

Questo sembra valido dalla bozza dello standard C ++ 11 , se consideriamo la sezione 5.2.3 Conversione esplicita del tipo (notazione funzionale) il paragrafo 2 dice ( enfasi mia ):

L’ espressione T () , dove T è un identificatore del tipo semplice o identificatore del tipo per un tipo di object completo non array o il tipo void (eventualmente qualificato per cv) , crea un valore prvalore del tipo specificato, il cui valore è tale prodotto da value-initializing (8.5) un object di tipo T; nessuna inizializzazione viene effettuata per il caso void (). […]

la formulazione è abbastanza simile pre C ++ 11 pure.

Questo va bene in un constexpr anche se la sezione 7.1.5 paragrafo 3 dice:

La definizione di una funzione di constexpr deve soddisfare i seguenti vincoli:

e include questo proiettile:

il suo tipo di ritorno deve essere di tipo letterale;

e void non è un letterale in C ++ 11 come nella sezione 3.9 paragrafo 10 , ma se guardiamo al paragrafo 6 , fornisce un’eccezione che si adatta a questo caso, dice:

Se la specializzazione del modello istanziata di un modello di funzione di constexpr o di una funzione membro di un modello di class non riuscirebbe a soddisfare i requisiti per una funzione constexpr o constexpr, tale specializzazione non è una funzione constexpr o un costruttore di constexpr. [Nota: se la funzione è una funzione membro, sarà comunque const come descritto di seguito. -End note] Se nessuna specializzazione del template produce una funzione constexpr o constexpr constructor, il programma è mal formato; nessuna diagnostica richiesta .

Come ha notato Casey nel progetto standard di C ++ 14, il vuoto standard è letterale , questa è la sezione 3.9 Tipi paragrafo 10 dice:

Un tipo è di tipo letterale, se è:

e include:

– vuoto; o

Vedi la risposta di @Shafik Yaghmour per le informazioni complete.

Il seguente paragrafo lo proibisce per non-templates (7.1.5 (3)):

La definizione di una funzione di constexpr deve soddisfare i seguenti vincoli:

  • […]

  • il suo tipo di ritorno deve essere un tipo letterale o un riferimento al tipo letterale

Per elaborare, un tipo letterale è definito in 3.9 (10) come un tipo scalare o una composizione di oggetti di tipo letterale in una matrice o una struttura. void non è un tipo scalare di 3.9 (9).

La tua funzione restituisce il valore di void() , non si sta ritornando da una funzione void di per sé. Stai restituendo un valore NULL . Quello che stai facendo è equivalente a questo:

 void f() { return void(); } 

Questo restituisce un valore nullo, l’unico valore void. non puoi restituire nient’altro da una funzione di vuoto perché sarà di un tipo diverso.