2013-06-08 21 views
11

Una funzione constexpr deve solo consistere in una dichiarazione di ritorno e ogni argomento dovrebbe essere noto al momento della compilazione:constexpr - perché solo una dichiarazione di ritorno?

// constexpr functions use recursion rather than iteration 
constexpr int factorial(int n) 
{ 
    return n <= 1 ? 1 : (n * factorial(n-1)); 
} 

Perché solo l'istruzione return? Voglio dire, perché questo è sbagliato?

// constexpr functions use recursion rather than iteration 
constexpr int factorial(int n) 
{ 
    int a = 222; //another variable 
    return n <= 1 ? 1 : (n * factorial(n-1)); 
} 
+7

Sospetto che sia solo un modo per semplificare le implementazioni del compilatore. – juanchopanza

+10

Perché lo standard dice così. Consentire funzioni più generali complicherebbe parecchio la vita degli scrittori di compilatori (in ogni caso, C++ 14 solleva alcune di queste restrizioni) –

+3

Perché consentire le variabili significherebbe aggiungere molte altre (più complicate) restrizioni. Così hanno mantenuto semplice la loro introduzione. Ci sono comunque dei modi per aggirare (chiamare una funzione 'constexpr' da un'altra, ad esempio) – Dave

risposta

6

Semplifica l'implementazione, come afferma Andy Prowl. Questo forse risponde "Perché", ma non dice come lo fa.

Una funzione con solo un valore di ritorno, e in particolare uno senza variabili locali, è una situazione speciale per un compilatore. Questa funzione è ora composta da una singola espressione: l'AST della funzione ha bisogno solo di avere una singola radice. Questa mancanza di variabili significa che questa espressione può essere valutata senza una macchina virtuale in piena regola per elaborarla, piuttosto può essere usato un semplice analizzatore di espressioni dell'albero. Per varie ragioni, il compilatore probabilmente dispone già di un simile valutatore o potrebbe crearne uno relativamente facilmente (diventa un passaggio per la semplificazione degli alberi).

Sapere che solo l'espressione constexpr viene utilizzata all'interno dell'espressione fornisce una semplificazione chiave. Questo garantisce che ogni vertice nella funzione AST abbia le stesse proprietà, anche se è una chiamata di funzione. L'intero meccanismo constexpr è quindi una forma generalizzata di const-folding. E sebbene non sia sempre fatto a questo alto livello nel compilatore, assicura che possa essere implementato senza uno sforzo enorme (rispetto a una VM completa).

Torna alla domanda "perché". La restrizione è determinata principalmente dalle limitazioni delle risorse sui fornitori. Questa funzionalità, come specificato, non è un grande sforzo e quindi i produttori possono effettivamente implementarlo in un ragionevole periodo di tempo. Se non c'erano tali restrizioni, in particolare consentendo le variabili locali, aumenta notevolmente la quantità di lavoro necessario. Dal punto di vista dell'utente (noi, i programmatori), le restrizioni sono comunque del tutto arbitrarie.

+0

Bella risposta. 'constexpr' in realtà chiede al compilatore di ** interpretarlo ** (piuttosto che compilare), quindi è comprensibile la ricerca della semplicità. Una bella aggiunta, tuttavia, sarebbe 'static if' (utile per' constexpr', non solo per i template), su quale stato non sono sicuro ora. – eudoxos

+0

Immagino che sia anche per un altro motivo. Non è possibile avere cicli infiniti e le chiamate ricorsive inifite possono essere rilevate semplicemente forzando un limite di ricorsione. Inoltre, qualsiasi modifica a constexpr che consente più cose implicherebbe anche invarianti più complessi che gli utenti devono rispettare per ottenere la compilazione del codice senza girovagare perché non si sta compilando. Inoltre ho il dubbio che in realtà tu debba anche "provare" che funziona il constexpr, e proarlo per codice arbitrario sarebbe difficile o impossibile anche dal punto di vista teorico. – GameDeveloper

13

Perché:

Perché constexpr è un concetto abbastanza nuovo e radicale in C++ 11 ed è difficile per la transizione un importante standard di linguaggio per qualcosa di completamente nuovo. Regole del conservatorismo

Per C++ 1y (attualmente indirizzato a C++ 14), il tuo esempio è legale. La punta del clang del tronco lo implementa già sotto il flag -std=c++1y.

Problemi correlati