Digitare la conversione all’argomento non di tipo template senza constexpr

Considera il seguente codice:

struct A { constexpr operator int() { return 42; } }; template  void foo() {} void bar(A a) { foo(); } int main() { foo(); const int i = 42; foo(); // (1) A a{}; static_assert(i == a, ""); bar(a); foo(); // error here } 

Clang 3.7 con c ++ 14 accetta questo, mentre gcc 5.2.0 con c ++ 14 non lo fa, producendo il seguente messaggio:

 /tmp/gcc-explorer-compiler1151027-68-1f801jf/example.cpp: In function 'int main()': 26 : error: the value of 'a' is not usable in a constant expression foo(); ^ 23 : note: 'a' was not declared 'constexpr' A a{}; ^ Compilation failed 

La modifica di a constexpr come suggerito da gcc corregge l’errore di compilazione gcc, ma senza constexpr , quale compilatore ha ragione?

Per me, sembra che a dovrebbe essere “utilizzabile in costante espressione”, come static_assert . Inoltre, il fatto che i possa essere usato allo stesso modo (segnato (1) ), e il fatto che compaia bar() , mi fa anche pensare che gcc sia sbagliato.

UPD : segnalato un bug contro gcc: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68588

La conversione definita dall’utente è consentita da [expr.const] / (4.1) e non vedo un singolo punto di riferimento applicabile in [expr.const] / 2 che impedisca un’espressione costante. In effetti, i requisiti sono così bassi che dichiarano a come

 A a; 

sta ancora dando un programma ben formato , anche se non aveva un constexpr predefinito di constexpr ecc., poiché l’operatore di conversione è constexpr e nessun membro viene valutato.

Come hai visto tu stesso, GCC è contraddittorio in quanto consente di static_assert condizione static_assert ma non in un argomento template.

Direi che Clang è corretto.

La bozza per C ++ corrente (n4296) dice:

14.3.2 Argomenti modello non di tipo [temp.arg.nontype]

Un argomento modello per un parametro modello non di tipo deve essere un’espressione costante convertita (5.20) del tipo del parametro modello

E 5.20 §4 dice (enfatizza il mio):

5.20 Espressioni costanti [expr.const]

(4) Un’espressione costante convertita di tipo T è un’espressione, convertita implicitamente in tipo T, in cui l’espressione convertita è un’espressione costante e la sequenza di conversione implicita contiene solo

(4.1) – conversioni definite dall’utente, …

IFAIK in foo(); a è convertito in int con una conversione definita dall’utente constexpr e come tale è un’espressione costante convertita.

Detto questo, non siamo lontani da un caso limite qui, e il mio consiglio sarebbe: non giocare con un tale costrutto nel codice di produzione 🙂

Come @ Jarod42 suggerisce che dovrebbe essere constexpr . Questo perché i template sono dedotti in fase di compilazione, e quindi anche gli argomenti non di tipo devono essere disponibili in fase di compilazione. constexpr è una promise che saranno disponibili al momento della compilazione.