l'intenzione del seguente codice C++ è di avvolgere l'operatore ternario (?:
) in una funzione separata, che in seguito aiuterà a costruire un albero di sintassi.Esempio di istogramma ricorsivo infinito quando si usa Clang mentre GCC funziona correttamente?
Prima di guardare reale C++ frammento diamo un rapido sguardo a ciò che fa in pseudo-codice:
bool recursive(bool v) {
return v ? v : recursive(v);
}
int main() {
bool r = recursive(true)
}
Purtroppo Clang ha problemi con che chiude la ricorsione quando l'operatore ternario (?:
) è avvolto all'interno di un modello funzione:
/****************** DECLARATIONS ******************/
template<typename T>
constexpr T
recursive(T t);
struct IfCase {
template<typename T>
constexpr T
operator()(T t) const;
};
struct ElseCase {
template<typename T>
constexpr T
operator()(T t) const;
};
#if defined(WORKS)
static constexpr bool
if_then_else_return(bool b, IfCase const& ic, ElseCase const& ec, bool x);
#else
template<typename T, typename IfFunctor, typename ElseFunctor>
static constexpr T
if_then_else_return(T b, IfFunctor const& ic, ElseFunctor const& ec, T x);
#endif
/****************** DEFINITIONS ******************/
template<typename T>
constexpr T
IfCase::operator()(T t) const {
return t;
}
template<typename T>
constexpr T
recursive(T t) {
return if_then_else_return(t, IfCase{}, ElseCase{}, t);
}
template<typename T>
constexpr T
ElseCase::operator()(T t) const {
return recursive(t);
}
#if defined(WORKS)
constexpr bool
if_then_else_return(bool b, IfCase const& ic, ElseCase const& ec, bool x) {
return b ? ic(x) : ec(x);
}
#else
template<typename T, typename IfFunctor, typename ElseFunctor>
constexpr T
if_then_else_return(T b, IfFunctor const& ic, ElseFunctor const& ec, T x) {
return b ? ic(x) : ec(x);
}
#endif
/****************** CALL ******************/
int main() {
constexpr auto r = recursive(true);
}
risultati Corporatura:
g ++ con reg. funzione (-DWORKS): OK
g ++ con tmpl. funzione: OK
clang ++ con reg. funzione (-DWORKS): OK (Find code & results also at Coliru)
clang ++ con tmpl. Funzione: FAIL (Find code & results also at Coliru)
GCC (4.9.2) compila entrambe le varianti senza errori, ma Clang (da 3.5 a 3.8) non riesce con il seguente messaggio di errore:
main.cpp:56:14: fatal error: recursive template instantiation exceeded maximum depth of 256
return b ? ic(x) : ec(x);
^
/*** the next error messages for lines 64, 38 and 56 are repeated several times ***/
main.cpp:56:22: note: in instantiation of function template specialization 'ElseCase::operator()<bool>' requested here
return b ? ic(x) : ec(x);
^
main.cpp:38:9: note: in instantiation of function template specialization 'if_then_else_return<bool, IfCase, ElseCase>' requested here
return if_then_else_return(t, IfCase{}, ElseCase{}, t);
^
main.cpp:64:21: note: in instantiation of function template specialization 'recursive<bool>' requested here
constexpr auto r = recursive(true);
^
1 error generated.
Ma perché? Come può essere riscritto questo codice in modo che Clang non si lamenti più?
Grazie mille in anticipo.
EDIT 1:
Ho un corto il messaggio del compilatore, si spera aumentando la sua leggibilità. Per un backtrace completo, si prega di dare un'occhiata a quei collegamenti Coliru forniti sopra.
La rimozione dello specificatore
constexpr
funzionerà attorno a questo errore Clang. Ma questo riduce anche la funzionalità e quindi non è un'opzione.
Si prega di trovare il codice & costruire risultati per GCC in Coliru [qui (. Funzione reg)] (http : //coliru.stacked-crooked.com/a/817e88c473b1a02e) e [qui (funzione tmpl.)) (http://coliru.stacked-crooked.com/a/af8253f0627e1543). – Jakob
Utilizzare un esempio [MCVE], allontanarsi. Nel caso di questa domanda, se riduci il problema a * un * errore dalla * una * funzione che produce l'errore, sarà più facile aiutarti. – NonCreature0714
Grazie per il tuo suggerimento! Se rimuovo 'constexpr' il problema è scomparso, ma questo ridurrà anche la funzionalità. Se rimuovo '# ifdef' ecc. IMHO è più difficile vedere cosa intendo con _reg. function_ e _tmpl. function_, ma posso rimuovere quelli se utili. Senza la divisione tra dichiarazioni e definizioni, ho avuto errori di compilazione con GCC. Che cosa hai esattamente in mente qui? – Jakob