2015-11-27 18 views
5

Si consideri il seguente codice:Tipo conversione al modello di non-tipo di argomento senza constexpr

struct A { 
    constexpr operator int() { return 42; } 
}; 

template <int> 
void foo() {} 

void bar(A a) { 
    foo<a>(); 
} 

int main() { 
    foo<A{}>(); 

    const int i = 42; 
    foo<i>(); // (1) 

    A a{}; 

    static_assert(i == a, ""); 
    bar(a); 
    foo<a>(); // error here 
} 

Clang 3.7 con C++ 14 accetta questo, mentre gcc 5.2.0 con C++ 14 non lo fa, la produzione del 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<a>(); 
^ 
23 : note: 'a' was not declared 'constexpr' 
A a{}; 
^ 
Compilation failed 

Modifica a essere constexpr come suggerito da gcc corregge l'errore di compilazione gcc, ma senza constexpr, che compi ha ragione?

Per me, sembra che a debba essere "utilizzabile in espressione costante", come certifica static_assert. Inoltre, il fatto che i possa essere utilizzato allo stesso modo (contrassegnato con (1)) e il fatto che compili lo bar(), mi fa anche pensare che gcc sia errato.

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

+0

Cambiare '' const' da opere constexpr' [ demo] (http://coliru.stacked-crooked.com/a/1bc480f2de523b5e). – Jarod42

+0

@ Jarod42, sì, vedi la mia modifica. – Petr

risposta

5

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. Infatti, i requisiti sono così sciolto che dichiara a come

A a; 

è still giving a well-formed program, anche se a non avere un costruttore di default constexpr ecc, in quanto l'operatore conversione è constexpr e nessun utente vengono valutati.

Come si è visto, GCC è contraddittorio in quanto consente a nella condizione static_assert ma non un argomento modello.

+0

Quindi questo è un errore di gcc? – Petr

+1

@Petr Certamente. – Columbo

-2

Come @ Jarod42 suggerisce a 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 promessa che saranno disponibili al momento della compilazione.

+0

Sono completamente consapevole del fatto che 'constexpr' risolve il problema (vedere anche la mia modifica). – Petr

+0

Se è così, allora questo dovrebbe dirvi quale implementazione è corretta. –

2

Direi che Clang è corretto.

Progetto per la corrente C++ (n4296) dice:

argomenti 14.3.2 Template non di tipo [temp.arg.nontype]

Un modello-argomento per un non-tipo di modello-parameter deve essere un'espressione costante convertito (5,20) del il tipo del modello di parametri

E 5.20 § 4 dice (sottolineare il mio):

5.20 Espressioni costanti [expr.const]

...

(4) Un convertito costante espressione di tipo T è un'espressione implicitamente convertito nel tipo T, dove convertito espressione è un'espressione costante e la sequenza conversione implicita contiene un'unica

(4,1) - conversioni definite dall'utente, ...

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

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

Problemi correlati