È sempre brutto contrassegnare una funzione C ++ constexpr?

21

Data una funzione molto banale,

int transform(int val) {
    return (val + 7) / 8;
}

Dovrebbe essere molto ovvio che sia facile trasformare questa funzione in una funzione constexpr , permettendomi di usarla quando definisco constexpr variabili, in questo modo:

constexpr int transform(int val) {
    return (val + 7) / 8;
}

La mia ipotesi è che questo sia strettamente un miglioramento, dal momento che la funzione può ancora essere chiamata in un contesto non- constexpr , e ora può essere utilizzata anche per aiutare a definire le variabili costanti in fase di compilazione.

La mia domanda è, ci sono situazioni in cui questa è una cattiva idea? Come, rendendo questa funzione constexpr , posso mai incontrare una situazione in cui questa funzione non sarà più utilizzabile in un circostanze particolari, o dove si comportano male?

    
posta Xirema 11.04.2017 - 21:05
fonte

2 risposte

16

Questo è importante solo se la funzione fa parte di un'interfaccia pubblica e si desidera mantenere le versioni future della tua API compatibile con i binari. In tal caso, devi riflettere attentamente su come vuoi evolvere la tua API e dove hai bisogno di punti di estensione per le modifiche future.

Questo rende un qualificatore constexpr una decisione di progettazione irrevocabile. Non puoi rimuovere questo qualificatore senza una modifica incompatibile con la tua API. Limita inoltre il modo in cui è possibile implementare quella funzione, ad es. non saresti in grado di fare alcuna registrazione all'interno di questa funzione. Non tutte le funzioni banali rimarranno banali nell'eternità.

Ciò significa che dovresti preferibilmente usare constexpr per le funzioni che sono intrinsecamente pure funzioni, e che sarebbe effettivamente utile in fase di compilazione (ad esempio per la metaprogrammazione del modello). Non sarebbe opportuno rendere le funzioni di constexpr solo perché l'attuale implementazione è consecutiva.

Quando la valutazione in fase di compilazione non è necessaria, l'utilizzo di funzioni inline o funzioni con collegamento interno sembrerebbe più appropriato di constexpr . Tutte queste varianti hanno in comune il fatto che il corpo della funzione è "pubblico" ed è disponibile nella stessa unità di compilazione della posizione della chiamata.

Se la funzione in questione non fa parte di un'API pubblica stabile, questo è meno di un problema dal momento che è possibile modificare arbitrariamente il progetto a piacimento. Ma dal momento che ora controlli tutti i siti di chiamata, non è necessario contrassegnare una funzione constexpr "nel caso in cui". conosci se stai usando questa funzione in un contesto di constexpr. L'aggiunta di qualificatori inutilmente restrittivi potrebbe quindi essere considerata offuscamento.

    
risposta data 11.04.2017 - 22:13
fonte
10

Contrassegnare una funzione come constexpr lo rende anche una funzione in linea § [dcl.constexpr] / 1:

A function or static data member declared with the constexpr specifier is implicitly an inline function or variable (7.1.6).

inline , a sua volta, significa che è necessario includere la definizione di tale funzione in ogni unità di traduzione in cui può essere utilizzata. Ciò significa fondamentalmente che le funzioni constexpr devono essere:

  1. limitato all'uso in un'unità di traduzione o
  2. definito in un'intestazione.

Le funzioni più tipiche che vuoi dichiarare in un'intestazione e definirle in un file sorgente (e qualsiasi altra cosa che le usi include solo l'intestazione, quindi i collegamenti al file oggetto di quella sorgente) constexpr semplicemente non funzionerà.

In teoria, suppongo che si possa semplicemente spostare tutto nelle intestazioni e avere un solo file sorgente che include solo tutte le intestazioni, ma ciò danneggerebbe drasticamente i tempi di compilazione e per i progetti più seri richiederebbe un'immensa quantità di memoria da compilare.

Anche una funzione constexpr è limitata in alcuni modi, quindi per alcune funzioni potrebbe non essere affatto un'opzione. Le restrizioni includono:

  1. le funzioni virtuali non possono essere constexpr .
  2. il suo tipo di ritorno deve essere un "tipo letterale" (ad es., nessun oggetto con i sensori o i ditor non-trival).
  3. tutti i suoi parametri devono essere di tipo letterale.
  4. il corpo della funzione non può contenere un blocco try .
  5. non può contenere una definizione di variabile di tipo non letterale o qualsiasi cosa con durata di memorizzazione statica o di thread.

Ho saltato un paio di cose piuttosto oscure (ad esempio, non può contenere nemmeno un'istruzione goto o asm ), ma hai un'idea: per un bel po 'di cose, ha appena vinto funziona.

In conclusione: sì, ci sono alcune situazioni in cui questa sarebbe una pessima idea.

    
risposta data 12.04.2017 - 00:07
fonte

Leggi altre domande sui tag