Using different code paths for compile-time runtime and replication, I was able to bypass infinite recursion:
#include <boost/hana/integral_constant.hpp> #include <boost/hana/unpack.hpp> #include <boost/hana/equal.hpp> #include <type_traits> #include <tuple> #include <cassert> namespace hana = boost::hana; namespace detail { /* std::forward_as_tuple(views...) is not constexpr */ template<typename... Xs> static constexpr auto forward_as_tuple(Xs&&... xs) { return std::tuple<Xs...>{ std::forward<Xs>(xs)... }; } /* namespace detail */ } template<typename Condition, typename LastStep, typename RecursionStep> struct functor_t { constexpr functor_t(Condition const c, LastStep ls, RecursionStep rs) : c{c}, ls{ls}, rs{rs} {}; template <typename Args> constexpr decltype(auto) eval(std::true_type, Args const& args) const { return hana::unpack(args, ls); } template <typename Args> constexpr decltype(auto) eval(std::false_type, Args const& args) const { auto vt = hana::unpack(args, rs); return eval( hana::unpack(vt, c), vt); } template <typename Args> constexpr decltype(auto) eval(hana::true_, Args const& args) const { return hana::unpack(args, ls); } template <typename Args> constexpr decltype(auto) eval(hana::false_, Args const& args) const { auto vt = hana::unpack(args, rs); return eval( hana::unpack(vt, c), vt); } template <typename Args> decltype(auto) eval(bool const& b, Args const& args) const { if (b) { return hana::unpack(args, ls); } auto vt = hana::unpack(args, rs); return eval(hana::unpack(vt, c), vt); } template <typename... Args> constexpr decltype(auto) operator()(Args&& ...args) const { return eval( c(std::forward<Args>(args)...), detail::forward_as_tuple(args...) ); } Condition const c; LastStep ls; RecursionStep rs; }; struct recurse_t { template <typename Condition, typename LastStep, typename RecursionStep> constexpr decltype(auto) operator()(Condition && c, LastStep && ls, RecursionStep && rs) const { return functor_t<Condition, LastStep, RecursionStep>{c, ls, rs}; } }; constexpr recurse_t recurse{}; /****************** TEST ******************/ #include <boost/hana/plus.hpp> #include <boost/hana/minus.hpp> #include <boost/hana/equal.hpp> #include <boost/hana/ext/std/tuple.hpp> #include <tuple> struct Condition { template<typename I, typename S, typename J> constexpr decltype(auto) operator()(I const& i, S const& s, J const& j) const{ return (j == hana::int_c<1>); } }; struct LastStep { template<typename I, typename S, typename J> constexpr decltype(auto) operator()(I const& i, S const& s, J const& j) const { return hana::plus(s, i); } }; struct RecursionStep { template<typename I, typename S, typename J> constexpr decltype(auto) operator()(I const& i, S const& s, J const& j) const { return std::make_tuple(i, hana::plus(s,i), j-hana::int_c<1>); } }; int main() { /* compute: 2*10 == 20 */ assert(recurse(Condition{}, LastStep{}, RecursionStep{})(2,0,10) == 20); static_assert(recurse(Condition{}, LastStep{}, RecursionStep{})(hana::int_c<2>, hana::int_c<0>, hana::int_c<10>) == hana::int_c<20>, ""); assert( recurse( [](auto a, auto b, auto c) { return (a == 1); }, [](auto a, auto b, auto c) { return a+b; }, [](auto a, auto b, auto c) { return std::make_tuple(a, a+b, c-1); } )(2,0,10) == 20 ); }