Recentemente ho fatto una domanda qui (Detecting instance method constexpr with SFINAE) dove ho provato a fare qualche rilevamento di constexpr in fase di compilazione. Alla fine, ho capito che si può sfruttare noexcept
per fare questo: qualsiasi espressione costante è anche noexcept
. Così ho messo insieme i seguenti macchinari:Decrittografia Constex
template <class T>
constexpr int maybe_noexcept(T && t) { return 0; }
...
constexpr bool b = noexcept(maybe_noexcept(int{}));
Questo funziona e b
è vero come ci si aspetterebbe, come zero-in fase di inizializzazione di un int
è un'espressione costante. Rende correttamente anche zero quando dovrebbe (se cambio int
in un altro tipo appropriato).
Successivamente, volevo controllare se qualcosa è constexpr
spostare costruibile. Quindi ho fatto questo:
constexpr bool b = noexcept(maybe_noexcept(int(int{})));
E ancora una volta, questo funziona correttamente per int
, o un tipo definito dall'utente. Tuttavia, questo controlla che il tipo abbia sia un costruttore constexpr predefinito sia un costruttore di movimento constexpr. Quindi, per ovviare a questo, ho provato a cambiare a declval:
constexpr bool b = noexcept(maybe_noexcept(int(declval<int>())));
Ciò si traduce in b
essere falsa a gcc 5.3.0 (non è possibile utilizzare clang per niente di tutto questo, perché clang non correttamente fa costante espressioni noexcept
). Nessun problema, dico, deve essere perché declval
è (abbastanza interessante) non contrassegnato constexpr
. Così scrivo la mia versione ingenua:
template <class T>
constexpr T&& constexpr_declval() noexcept;
Sì, questo è ingenuo rispetto a come la libreria standard lo fa in quanto sarà soffocare sul vuoto e probabilmente altre cose, ma va bene per ora. Così cerco di nuovo:
constexpr bool b = noexcept(maybe_noexcept(int(constexpr_declval<int>())));
Questo non funziona ancora, b
è sempre false. Perché questa non è considerata un'espressione costante? Si tratta di un bug del compilatore o non sto capendo di fondamentale su constexpr
? Sembra che ci sia una strana interazione tra constexpr
e contesti non valutati.
@ Cameron La seconda parte di ciò che hai detto è certamente vera, ma il primo tecnicamente non lo è. Ogni espressione costante * è * '' noexcept'', non è che possa essere. Tuttavia, il ritorno di una funzione '' constexpr'' non è sempre un'espressione costante. –
La chiamata di funzione non è un'espressione costante perché non è definita ([expr.const] /2.3) – 0x499602D2