zamiarem następującego kodu C++ jest owinięcie trójskładnikowego operatora (?:
) w oddzielną funkcję, która później pomoże w budowaniu drzewa składni.Nieskończona rekurencyjna instancja szablonu podczas używania Clanga, podczas gdy GCC działa dobrze?
Przed patrząc na realne C++ fragment rzućmy okiem na to, co robi w pseudo kod:
bool recursive(bool v) {
return v ? v : recursive(v);
}
int main() {
bool r = recursive(true)
}
Niestety Clang ma problemy z zakończenia rekurencji gdy operator trójskładnikowych (?:
) jest owinięty w szablonie funkcja:
/****************** 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);
}
wyniki produkcji:
g ++ z reg. funkcja (-DWORKS): OK
g ++ z tmpl. funkcja: OK
clang ++ z reg. funkcja (-DWORKS): OK (Find code & results also at Coliru)
clang ++ z tmpl. Funkcja: FAIL (Find code & results also at Coliru)
GCC (4.9.2) zestawia oba warianty bez błędu, ale Clang (3,5 do 3,8) nie powiedzie się z następującym komunikatem o błędzie:
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.
ale dlaczego? W jaki sposób można przepisać ten kod, aby Clang już nie narzekał?
Dziękuję bardzo z góry.
EDIT 1:
Mam zwarte komunikat kompilatora, mam nadzieję, że zwiększenie jego czytelności. Aby uzyskać pełny ślad, proszę spojrzeć na powyższe linki Coliru.
Usunięcie specyfikatora
constexpr
spowoduje obejście tego błędu Clang. Ale to również zmniejsza funkcjonalność, a zatem nie jest opcją.
Proszę znaleźć kod i budować wyników dla GCC na Coliru [tutaj (. Reg funkcji)] (http : //coliru.stacked-crooked.com/a/817e88c473b1a02e) i [tutaj (funkcja tmpl)] (http://coliru.stacked-crooked.com/a/af8253f0627e1543). – Jakob
Proszę użyć przykładu [MCVE], odejść. W przypadku tego pytania, jeśli zmniejszysz problem do * jednego * błędu z * jednej * funkcji, która powoduje błąd, łatwiej ci będzie pomóc. – NonCreature0714
Dziękujemy za podpowiedź! Jeśli usunę "constexpr", problem zniknie, ale zmniejszy to również funkcjonalność. Jeśli usuniemy '# ifdef' itp., IMHO jest trudniej zobaczyć, co mam na myśli z _reg. function_ i _tmpl. function_, ale mogę je usunąć, jeśli jest to pomocne. Bez podziału na deklaracje i definicje miałem błędy kompilacji z GCC. Co dokładnie miałeś tutaj na myśli? – Jakob