// { dg-do compile { target c++17 } } #include #include #include #define LIFT_FWD(x) std::forward(x) template inline constexpr auto equal( T &&t) { return [t = std::forward(t)](const auto& obj) -> decltype(obj == t) { return obj == t; }; } template struct is_tuple_invocable; template struct is_tuple_invocable> { using type = typename std::is_invocable::type; }; template inline constexpr auto compose( F&& f ) noexcept -> F { return std::forward(f); } namespace detail { template inline constexpr auto compose( std::true_type, F&& f, Tail&& tail, T&& ... objs) noexcept(noexcept(f(tail(std::forward(objs)...)))) -> decltype(f(tail(std::forward(objs)...))) { return f(tail(std::forward(objs)...)); } } template inline constexpr auto compose( F&& f, Fs&&... fs) { return [f = std::forward(f), tail = compose(std::forward(fs)...)] (auto&& ... objs) -> decltype(detail::compose(typename std::is_invocable(fs)...)), decltype(objs)...>::type{}, f, compose(std::forward(fs)...), LIFT_FWD(objs)...)) { using tail_type = decltype(compose(std::forward(fs)...)); #ifndef NOT_VIA_TUPLE using args_type = std::tuple; constexpr auto unitail = typename is_tuple_invocable::type{}; #else constexpr auto unitail = typename std::is_invocable::type{}; #endif return detail::compose(unitail, f, tail, LIFT_FWD(objs)...); }; } template constexpr auto eq = equal(N); static_assert(compose(eq<3>, std::plus<>{})(1,2), "compose is constexpr");