2015-12-14 18 views
7

Per esempio il codice qui sotto non compilare a meno incr() viene dichiarata constexpr:Dove in C++ 14 Standard si dice che una funzione non-constexpr non può essere utilizzata in una definizione di una funzione constexpr?

int incr(int& n) { 
    return ++n; 
} 

constexpr int foo() { 
    int n = 0; 
    incr(n); 
    return n; 
} 

Guardando §7.1.5/3 in C++ 14 abbiamo:

La definizione di un la funzione constexpr deve soddisfare i seguenti vincoli :
(3.1) - non deve essere virtuale (10.3);
(3.2) - il suo tipo di reso deve essere di tipo letterale;
(3.3) - ciascuno dei suoi tipi di parametri deve essere di tipo letterale;
(3,4) - la sua funzione-corpo sarà = eliminare, = default, o un composto-dichiarazione che non contiene

(3.4.1) - un asm-definizione,
(3.4.2) - un'istruzione goto,
(3.4.3) - una prova-blocco, o
(3.4.4) - una definizione di una variabile di tipo non letterale oppure di durata statica o di stoccaggio filo o per i quali nessuna inizializzazione viene eseguita.

+0

Probabilmente la pena notare [domanda precedente] (http://stackoverflow.com/q/34211688/1708801) che copre molto stesso terreno, anche se da una prospettiva differente . –

+0

@ShafikYaghmour Mi piacerebbe davvero avere i vostri commenti su questa nuova domanda. – Ayrosa

+0

nota che le cose che hai citato sono * necessarie * ma non * sufficienti * condizioni, cioè se tali condizioni sono violate, allora il codice è mal formato, tuttavia se non vengono violate allora il codice può essere o non essere corretto e noi devono guardare ad altre parti della specifica. –

risposta

10

due paragrafi dopo, nel [dcl.constexpr]/5:

per un non-modello, non-default constexpr funzione o di un non-modello, non in default, non ereditando costruttore di constexpr, se non esiste alcun valore di argomento tale che un'invocazione della funzione o del costruttore possa essere una sottoespressione valutata di un'espressione della costante di nucleo (5.20) o, per un costruttore, un iniziatore costante per alcuni oggetti (3.6.2) il programma è mal formato; nessuna diagnostica richiesta.

Nessun argomento esiste tale che foo() potrebbe essere un nucleo espressione costante a causa di incr(), quindi il programma è mal-formata (NDR).

+0

Non penso che §7.1.5/5 non abbia nulla a che fare con la domanda. Per esempio, dove nello Standard, si dice che il corpo di una funzione di constexpr deve essere un'espressione costante di base? – Ayrosa

+0

@Ayrosa: proprio lì in quella citazione. "un'invocazione della funzione o del costruttore potrebbe essere una sottoespressione valutata dell'espressione di una costante di nucleo" Ma non è l'intero corpo che deve essere, ma solo le parti valutate. –

+0

@BenVoigt Ma ancora, non dice che il corpo di una funzione di constexpr è un'espressione costante di base. – Ayrosa

4

Non funziona.

è consentito Di seguito, anche se fa esattamente ciò che si intuisce è vietato:

int incr(int& n) { 
    return ++n; 
} 

constexpr int foo(bool x) { 
    int n = 0; 
    if (x) incr(n); 
    return n; 
} 

Il codice nella tua domanda non è consentita dalla regola con Barry citato nella sua risposta. Ma nella mia variante esiste un set di parametri (in particolare, false) con il quale l'invocazione di foo genera un'espressione costante in fase di compilazione.

Nota che non è richiesta una diagnostica: un compilatore conforme potrebbe consentire la compilazione della versione.

+1

Vale la pena notare che g ++ non riesce a compilare entrambe le versioni, dando lo stesso (errato) messaggio di errore in entrambi i casi. clang ++ compila questo e rifiuta quello originale, citando la ragione corretta: "la funzione constexpr non produce mai un'espressione costante". –

+1

@ n.m. Quel bug è stato risolto nel trunk gcc – bames53

+0

Mi ci è voluto un po 'per apprezzare davvero la qualità di entrambe le risposte, le tue e quelle di bames53 (+1). – Ayrosa

8

Quello che stai cercando è § 5.19:

A condizionale espressionee è un nucleo costante espressione a meno che la valutazione del e, seguendo le regole della macchina astratta (1.9), valuterà una delle seguenti espressioni:

Questo si applica alla valutazione di un'espressione che è una chiamata di funzione constexpr. Cioè, chiamare una funzione constexpr sarà una 'espressione costante di nucleo' se la valutazione della funzione, cioè l'esecuzione del corpo della funzione secondo le regole della macchina astratta C++, non fa nessuna delle cose proibite nell'elenco dato in § 5.19.

Uno degli elementi della lista è:

  • un'invocazione di una funzione diversa da [...] una funzione constexpr

Quindi, per applicare questo al tuo esempio : la valutazione dell'espressione foo() valuta una chiamata a una funzione incr() che non è una funzione di constexpr, il che significa che l'espressione foo() non è un'espressione di costante di nucleo.

Inoltre, dal momento che quanto sopra è vero per tutte le possibili invocazioni della vostra funzione foo, la regola al § 7.1.5/5 calci e significa che il programma esempio è mal formato, senza diagnostica richiesta, anche se non si in realtà chiamare foo().


Come Ben Voigt indica una funzione constexpr può contenere chiamate a funzioni non consexpr, purché la valutazione particolare della funzione realtà non valutare tale chiamata di funzione (o appare in un contesto che fa non richiede un'espressione costante).

Le restrizioni in 5.19 riguardano solo le espressioni che vengono effettivamente valutate come parte della valutazione di un'espressione.

Ad esempio:

#include <iostream> 

int incr(int &n) { return ++n; } 

enum E {be_constexpr, not_constexpr}; 

constexpr int foo(E e = be_constexpr) { 
    int n = 0; 
    if (e == not_constexpr) { incr(n); } 
    return n; 
} 

int main() { 
    constexpr int a = foo(); // foo() is a constant expression 
    int b = foo(not_constexpr); // may or may not evaluate `foo(non_constexpr)` at runtime. In practice modern C++ compilers will do compile-time evaluation here even though they aren't required to. 
    // constexpr int c = foo(not_constexpr); // Compile error because foo(not_constexpr) is not formally a constant expression, even though modern compilers can evaluate it at compile-time. 

    std::cout << a << ' ' << b << '\n'; 
} 
+0

Mi ci è voluto un po 'per apprezzare davvero la qualità di entrambe le risposte, le tue e quelle di Ben Voigt (+1). – Ayrosa

Problemi correlati