the intention of the following c++ code is to wrap the ternary operator (?:
) in a separate function, which later on will help with building a syntax tree.
Before looking at real c++ snippet let's take a quick look at what it does in pseudo code:
bool recursive(bool v) {
return v ? v : recursive(v);
}
int main() {
bool r = recursive(true)
}
Unfortunatly Clang has problems with terminating the recursion when the ternary operator (?:
) is wrapped within a template function:
/****************** 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);
}
Build results:
g++ with reg. function (-DWORKS): OK
g++ with tmpl. function: OK
clang++ with reg. function (-DWORKS): OK (Find code & results also at Coliru)
clang++ with tmpl. function: FAIL (Find code & results also at Coliru)
GCC (4.9.2) compiles both variants without an error, but Clang (3.5 to 3.8) fails with the following error message:
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.
But why? How can this code be rewritten so that Clang does not complain anymore?
Thank you very much in advance.
EDIT 1:
I've shorted the compiler message, hopefully increasing its readability. For a full backtrace, please take a look at those Coliru links provided above.
Removing the
constexpr
specifier will work around this Clang error. But this also reduces functionality and thus is not an option.