2012-11-08 16 views
11

durante la visualizzazione di una delle mie vecchie domande su constexpr mi sono imbattuto in un commento molto importante (IMHO). In pratica si riduce a: (questo è legale C++ 11 :()Perché constexpr funziona con le funzioni impure

constexpr double f(bool b) 
{ 
return b? 42:42/(rand()+1); // how pure is rand ;) 
} 

La mia domanda è che cosa è la ragione per cui questo è consentito dallo standard Poiché Im un grande fan di trasparenza referenziale spero. hanno una buona ragione :) e mi piacerebbe saperlo.

BTW vi è correlato Q ma la maggior parte della A non menziona nemmeno la cosa pura, o quando lo fanno non specificano il ragionamento per cui std lo consente. Relation between constexpr and pure functions

+1

rand() è un constexpr? – Yakk

+1

no it isnt, ecco perché ho inserito;) nei commenti – NoSenseEtAl

risposta

7

La parola constexpr nella definizione della funzione informa il compilatore che questa funzione può essere eseguito al momento della compilazione se i tutti gli argomenti e le variabili sono noti al momento della compilazione stessa. Non esiste tale garanzia, ad esempio, quando alcuni valori possono essere noti solo in fase di esecuzione nel , nel qual caso la funzione verrà eseguita in fase di esecuzione.

Tuttavia, non ha nulla a che fare con pura o impura, dal momento che questi termini implicano che l'uscita dipende dagli ingressi solo, e non importa quante volte si chiama la funzione con gli stessi valori dei parametri di input , l'output sarà lo stesso ogni volta, indipendentemente dal fatto che sia calcolato in fase di compilazione o in runtime.

Esempio,

constexpr int add(int a, int b) { return a + b; } //pure! 

const int a = 2, b = 3; //const 
int c = 2, d = 3;  //non-const 

//we may read update c and d here! 

const int v1 = add(2,3); //computed at compile-time 
const int v2 = add(a,3); //computed at compile-time 
const int v3 = add(2,b); //computed at compile-time 
const int v4 = add(a,b); //computed at compile-time 

const int v3 = add(c,3); //computed at runtime 
const int v3 = add(c,b); //computed at runtime 
const int v3 = add(a,d); //computed at runtime 
const int v3 = add(c,d); //computed at runtime 

noti che qui add è una pura funzione indipendentemente dal fatto che viene calcolata al momento della compilazione o esecuzione.

+1

Qualsiasi funzione pura può essere valutata in fase di compilazione sotto la regola as-if, indipendentemente da 'constexpr'. Si chiama piegamento costante. Il 'constexpr' nel tuo esempio non sembra fare alcuna differenza. – Potatoswatter

+1

@Potatoswatter: vuoi dire che possiamo scrivere 'std :: array a;' anche se 'add' non è' constexpr'? Io non la penso così – Nawaz

+1

Intendevo nel tuo esempio: v). (La tua risposta non sembra affrontare i contesti di espressioni costanti.) I [ha aperto una domanda] (http://stackoverflow.com/questions/14472359/why-do-we-need-to-mark-functions-as -constexpr? lq = 1) sul fatto che 'std :: array ' sarebbe una cosa negativa. – Potatoswatter

6

Perché per alcuni domini dei parametri di input, il percorso impuro non verrà mai eseguito. Per quel dominio, constexpr funzionerà bene.

Ad esempio, la funzione potrebbe avere un ramo semplice e un ramo più complicato. E si può specificare che, affinché la propria funzione sia utilizzabile in espressioni costanti, gli argomenti della funzione devono essere tali per cui questa e quella condizione sono soddisfatte, cedendo al semplice ramo nella propria funzione che è sempre puro.

Un utile effetto laterale di questo è che è possibile causare errori durante il calcolo costante. Cioè se una precondizione nel ramo semplice viene violata, si potrebbe causare la valutazione di un'espressione impura, provocando un errore di compilazione (un'asserzione o un'eccezione è una buona idea qui, poiché continua a lamentarsi quando la funzione viene invocata in un contesto di runtime).

9

Nella norma, il requisito pertinente è nascosto sotto l'elenco principale dei requisiti per le funzioni constexpr. È in §7.1.5/5:

Per una funzione constexpr, se nessun valore funzione degli argomenti esistono tale che la sostituzione invocazione funzione produrrebbe un'espressione costante (5.19), il programma è mal formata; nessuna diagnostica richiesta.

§5.19 definisce i requisiti per le espressioni costanti, in modo tale che non è possibile chiamare rand().

La restrizione rilassata consente di disporre di funzioni che sono condizionatamente pure. Il tuo esempio f(true) è un argomento modello valido, ma non lo è f(false).

Lo svantaggio, ovviamente, è che il compilatore non verificherà che una funzione constexpr possa effettivamente essere utilizzata per lo scopo previsto. Devi scrivere casi di test.

Ah, la risposta di litb è corretta. (Ma questo è formulato più semplicemente.)

+1

Questa è la risposta giusta. – Omnifarious

+1

È anche una risposta migliore perché cita la sezione pertinente dello standard e fornisce una buona spiegazione di cosa significa. – Omnifarious

Problemi correlati