2016-03-31 10 views
16

Il costruttore di default di std::chrono::duration è definito come segue:Come può essere std :: chrono :: duration :: duration() constexpr?

constexpr duration() = default;

(. Ad esempio, vedere cppreference.com o della sorgente libstdC++)

Tuttavia, cppreference.com also says this circa constexpr costruttori:

Un costruttore di constexpr deve soddisfare i seguenti requisiti:

...

ogni classe base e ogni membro non statico deve essere inizializzato, sia nell'elenco costruttori inizializzazione o da un elemento di rinforzo o uguale inizializzatore. Inoltre, ogni costruttore coinvolto deve essere un costruttore constexpr ed ogni clausola di ogni inizializzatore brace o uguale deve essere un'espressione costante

E nel caso in cui ero confuso circa costruttori predefiniti, cppreference.com seems to say che costruttori di default hanno portato in essere con = default non sono definiti in modo diverso rispetto ai costruttori impliciti di default.

Tuttavia, il tipo rep per (la maggior parte) durate è un tipo intero nudo. Quindi, qualora l'esplicito costruttore di default per = defaultduration essere equivalente a

constexpr duration() {}

che ovviamente avrebbe lasciato la variabile membro intero di tipo duration::rep inizializzata? E, in effetti, non è il comportamento standard di duration tale che i valori predefiniti sono non inizializzati? (Ma non riesco a trovare un punto di riferimento che dice in modo esplicito questo.)

Così come può il costruttore = default per duration essere constexpr se lascia una variabile membro non statico inizializzata? Cosa mi manca?

+0

Credo che questo significhi che gli implementatori ci hanno in fase di inizializzazione della classe. – NathanOliver

+0

È 'constexpr' su un temploid, quindi anche se la versione di default non soddisfa il requisito di un costruttore di constexpr è ancora OK - non può essere usato solo in espressioni costanti. –

+0

'duration :: rep' è un tipo, non un membro, non è vero? – AndyG

risposta

11

7.1.5 L'identificatore constexpr [dcl.constexpr] dice:

La definizione di un costruttore constexpr devono soddisfare i seguenti requisiti:

  • la classe non deve avere tutte le classi base virtuali;
  • per un costruttore di copia/spostamento predefinito, la classe non deve avere un subobject mutabile che è un membro variante;
  • ciascuno dei tipi di parametri deve essere di tipo letterale;
  • il suo corpo di funzione non deve essere un blocco di prova di funzione;

Inoltre, sia la sua funzione-corpo sarà = cancella, o che essa deve soddisfare i seguenti requisiti:

  • sia la sua funzione-corpo sarà = default, o il composto-dichiarazione di il suo corpo di funzioni deve soddisfare i requisiti per un corpo di funzione di una funzione di constexpr;
  • ogni oggetto dati non statico non statico e oggetto secondario classe base deve essere inizializzato (12.6.2);
  • se la classe è un'unione con membri varianti (9.5), esattamente uno di essi deve essere inizializzato;
  • se la classe è una classe simile a un sindacato, ma non è un sindacato, per ciascuno dei suoi membri di un sindacato anonimo che hanno membri varianti, esattamente uno di deve essere inizializzato;
  • per un costruttore non delegante, ogni costruttore selezionato per inizializzare membri di dati non statici e oggetti secondari di classe base deve essere un costruttore di constexpr;
  • per un costruttore delegante, il costruttore di destinazione deve essere un costruttore di constexpr.

In poche parole, = default è una definizione valida di un costruttore constexpr predefinito finchè gli altri requisiti di cui sopra siano soddisfatte.

Quindi, come funziona con le costruzioni non inizializzate?

Non funziona.

Ad esempio:

constexpr seconds x1{}; 

Le opere di cui sopra e inizializza x1-0s. Tuttavia:

constexpr seconds x2; 

error: default initialization of an object of const type 'const seconds' 
     (aka 'const duration<long long>') without a user-provided default 
     constructor 
    constexpr seconds x2; 
        ^
         {} 
1 error generated. 

in modo da creare un constexpr di default costruito duration, è necessario zero inizializzare esso. E l'implementazione = default consente l'inizializzazione da zero a {}.

completa demo di lavoro:

template <class Rep> 
class my_duration 
{ 
    Rep rep_; 
public: 
    constexpr my_duration() = default; 
}; 


int 
main() 
{ 
    constexpr my_duration<int> x{}; 
} 

Interessante Sidebar

ho imparato qualcosa per iscritto questa risposta, e ha voluto condividere:

Continuavo a chiedermi il motivo per cui il seguente non funziona :

Perché rendere questa classe non-template interrompe il costruttore di default constexpr ?!

Poi ho provato questo:

using Rep = int; 

class my_duration 
{ 
    Rep rep_; 
public: 
    my_duration() = default; // removed constexpr 
}; 


int 
main() 
{ 
    constexpr my_duration x{}; 
} 

E i compilatori come nuovo.

Se non c'è già un problema CWG, probabilmente dovrebbe esserlo. Il comportamento sembra un po 'incoerente. E questo è probabilmente solo perché noi (l'intero settore) stiamo ancora imparando a conoscere constexpr.

+0

Ma all'interno delle funzioni 'constexpr', si potrebbe fare' constexpr auto fun() {secondi x2; x2 = seconds {}; ritorno x2; } ', giusto? – TemplateRex

+0

@TemplateRex: clang non piace. Si lamenta della costruzione di 'x2'. Anche usando qualcosa di simile a tip-of-trunk e usando '-std = C++ 1z'. –

+0

hmm, infatti. Ho erroneamente ricordato parte del mio codice che ha eseguito l'inizializzazione in 2 passaggi, ma quelle classi avevano inizializzatori in-classe con '= default' sul costruttore quindi erano in realtà' constexpr'. – TemplateRex