Cosa determina se una funzione constexpr è un'espressione costante?

Nov 30 2020

(il compilatore utilizzato è gcc con c ++ 17 per quanto ne so (difficile da trovare in visual studio))

#include <iostream>

using namespace std;

void increment( int& v )
{
    ++v;
}

int constexpr f()
{
    int v = 0;
    increment( v );
    return v;
}

int main( )
{
    cout << f( ) << '\n';
}

Il codice sopra fornisce l'errore durante la compilazione:

la funzione constexpr 'f' non può dare come risultato un'espressione costante.

A quanto ho capito questo è perché la funzione incrementnon è un constexpr. Quello che mi confonde è che il seguente codice si compila bene:

#include <iostream>

using namespace std;

void increment( int& v )
{
    ++v;
}

int constexpr f()
{
    int v = 0;
    for( int i = 0; i < 1; ++i )
    {
        increment( v );
    }   
    return v;
}

int main( )
{
    cout << f( ) << '\n';
}

Questo codice è funzionalmente lo stesso e si compila, anche se l'incremento non è ancora un constexpr. Non capisco come sia possibile che un ciclo for attraverso l'intervallo [0, 1) induca il compilatore a rendersi conto che la funzione in frealtà è un constexpr.

Se qualcuno può fornire alcune informazioni su constexpr in c ++ e questa apparente incoerenza, lo apprezzerei molto.

Risposte

12 aschepler Nov 30 2020 at 22:23

Entrambi i programmi sono "mal formati, nessuna diagnostica richiesta", secondo [dcl.constexpr] / 6 :

Per una funzione constexpr o un costruttore constexpr che non è né predefinito né un modello, se non esistono valori di argomento tali che un'invocazione della funzione o del costruttore possa essere una sottoespressione valutata di un'espressione costante di base o, per un costruttore, una sottoespressione valutata di la piena espressione di inizializzazione di qualche oggetto inizializzato con una costante ( [basic.start.static] ), il programma è mal formato, non è richiesta alcuna diagnostica.

È un po 'strano che gcc non riesca a notare il problema con il secondo programma, ma è ancora conforme.

Si noti che una diagnostica sarebbe necessaria se fvenisse utilizzata in un contesto che richiede effettivamente un'espressione costante, ad esempio constexpr int n = f();.

Alcune cose non sono mai consentite in una funzione constexpr. Questi richiedono una diagnostica (in genere un messaggio di errore), anche se la funzione non viene mai utilizzata in un'espressione costante - vedere la risposta di cigien . Ma i programmi nella domanda non violano nessuna di queste regole più severe.

6 cigien Nov 30 2020 at 22:27

Poiché non stai chiamando fun'espressione costante, la tua domanda è chiedere se il compilatore è tenuto a diagnosticare che fnon può essere chiamato in un'espressione costante, in base esclusivamente alla sua definizione .

I requisiti per la definizione di una constexprfunzione sono elencati qui :

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

(3.1) il suo tipo restituito (se presente) deve essere un tipo letterale;

(3.2) ciascuno dei suoi tipi di parametro deve essere un tipo letterale;

(3.3) non deve essere una coroutine;

(3.4) se la funzione è un costruttore o un distruttore, la sua classe non deve avere classi di base virtuali;

(3.5) il suo organo di funzione non deve racchiudere

(3.5.1) un'istruzione goto,

(3.5.2) un'etichetta identificativa,

(3.5.3) una definizione di una variabile di tipo non letterale o di durata di archiviazione statica o di thread.

Come si può vedere, la definizione di fnon viola nessuno dei requisiti nell'elenco. Quindi un compilatore è conforme se sceglie di non diagnosticare questo.

Come sottolineato nella risposta di Aschepler , constexprfunzioni del genere fnon possono essere chiamate in un'espressione costante, ma non sono diagnosticabile come tali, sono considerate mal formate, non diagnostiche richieste.

2 MarshallClow Nov 30 2020 at 22:22

In realtà non stai "chiamando" fin fase di compilazione.

se la tua funzione principale include: static_assert(f() == 1, "f() returned 1");sospetto che riceverai un errore "f () non è un'espressione costante".

Ecco una domanda correlata

Sneftel Nov 30 2020 at 22:12

Lo standard richiede che una constexprfunzione sia effettivamente valutabile in fase di compilazione per alcuni set di parametri ma non per tutti. Non richiede ai compilatori di diagnosticare una constexprfunzione che esegue certe cose che potrebbero non essere compilate in alcune circostanze, o anche se tale funzione ha un tale insieme di parametri. Questo evita loro di dover risolvere il problema dell'arresto.