È mai male contrassegnare una funzione C ++ constexpr?


26

Data una funzione molto banale,

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

Dovrebbe essere molto ovvio che è facile trasformare questa funzione in una constexprfunzione, permettendomi di usarla durante la definizione delle constexprvariabili, in questo modo:

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

La mia ipotesi è che questo è strettamente un miglioramento, poiché la funzione può ancora essere chiamata in un non constexprcontesto e ora può anche essere utilizzata per aiutare a definire variabili costanti in fase di compilazione.

La mia domanda è: ci sono situazioni in cui questa è una cattiva idea? Ad esempio, facendo questa funzione constexpr, posso mai incontrare una situazione in cui questa funzione non sarà più utilizzabile in una particolare circostanza o in cui si comporterà?


1
L'unica cosa a cui potevo pensare erano i bug del compilatore. È possibile che una chiamata di funzione constexpr ricorsiva possa causare una fase di compilazione molto lenta o persino un arresto anomalo della memoria del compilatore.
Zan Lynx,

Risposte:


19

Ciò è importante solo se la funzione fa parte di un'interfaccia pubblica e si desidera mantenere le versioni future dell'API compatibili con i binari. In tal caso, devi pensare attentamente a come vuoi far evolvere la tua API e dove hai bisogno di punti di estensione per future modifiche.

Ciò rende un constexprqualificatore una decisione di progetto irrevocabile. Non è possibile rimuovere questo qualificatore senza una modifica incompatibile all'API. Limita anche il modo in cui è possibile implementare quella funzione, ad esempio non si sarebbe in grado di effettuare alcuna registrazione all'interno di questa funzione. Non tutte le funzioni banali rimarranno banali nell'eternità.

Ciò significa che è preferibile utilizzarlo constexprper funzioni intrinsecamente pure e che sarebbero effettivamente utili in fase di compilazione (ad es. Per la metaprogrammazione del modello). Non sarebbe utile rendere le funzioni costexpr solo perché l'implementazione corrente sembra essere in grado di supportare.

Laddove la valutazione in fase di compilazione non è necessaria, l'utilizzo di funzioni inline o di funzioni con collegamento interno sembrerebbe più appropriato 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 un problema poiché puoi arbitrariamente cambiare il design a piacimento. Ma poiché ora controlli tutti i siti di chiamata, non è necessario contrassegnare una funzione constexpr "per ogni evenienza". Si sa se si sta utilizzando questa funzione in un contesto constexpr. L'aggiunta di qualificazioni inutilmente restrittive potrebbe quindi essere considerata offuscata.


12

Contrassegnare una funzione in quanto la constexprrende anche una funzione incorporata § [dcl.constexpr] / 1:

Una funzione o un membro di dati statici dichiarato con l'identificatore constexpr è implicitamente una funzione o variabile inline (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 sostanzialmente che le constexprfunzioni devono essere:

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

Le funzioni più tipiche che si desidera dichiarare in un'intestazione e definite in un file sorgente (e qualsiasi altra cosa che le utilizza include solo l'intestazione, quindi i collegamenti al file oggetto di quella fonte) constexprsemplicemente non funzionerà.

In teoria, suppongo che potresti semplicemente spostare tutto nelle intestazioni e avere un solo file sorgente che includa solo tutte le intestazioni, ma ciò danneggerebbe drasticamente i tempi di compilazione e per la maggior parte dei progetti seri richiederebbe enormi quantità di memoria da compilare.

Una constexprfunzione è anche 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 esempio, nessun oggetto con inseguitori o trici non trivalenti).
  3. tutti i suoi parametri devono essere di tipo letterale.
  4. il corpo della funzione non può contenere un tryblocco.
  5. non può contenere una definizione variabile di tipo non letterale o qualsiasi cosa con durata di archiviazione statica o thread.

Ho saltato un paio di cose piuttosto oscure (ad esempio, non può contenere nemmeno una gotoo una asmdichiarazione), ma ottieni l'idea - per un bel po 'di cose, semplicemente non funzionerà.

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


"non deve essere virtuale (fino a C ++ 20)" Mi chiedo come una funzione virtuale possa essere constexpr? Cosa fanno i compilatori?
Chaosink,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.