Is there any way to wrap any overloaded function into a function object?

Viewed 129

I was inspired from the C++ Ranges style for creating overloads of operator() inside the class and I found it very useful in many cases:

  • Can be passed as an argument directly like lambda but unlike overloaded functions.
  • Protected from ADL.
  • Preventing from specifying template arguments (closely, but .template operator()<...>)

For easy cases, I can handle it manually:

For overloaded function:

template <typename F, typename G>
constexpr auto compose(F&& f, G&& g) {
    return [
        f = std::forward<F>(f),
        g = std::forward<G>(g)
    ]<typename... Ts>(Ts&&... args) {
        if constexpr (std::is_void_v<std::invoke_result_t<G, Ts...>>) {
            std::invoke_r<void>(g, std::forward<Ts>(args)...);
            return std::invoke(f);
        } else {
            return std::invoke(f, std::invoke(g, std::forward<Ts>(args)...));
        }
    };
}

template <typename F, typename... Fs>
constexpr auto compose(F&& f, Fs&&... fs) {
    return compose(std::forward<F>(f), compose(std::forward<Fs>(fs)...));
}

For Function Object:

namespace functors {
  struct compose_fn {
    template <typename... Fs>
    constexpr auto operator()(Fs&&... fs) const noexcept {
      return ::compose(std::forward<Fs>(fs)...);
    }
  };
  inline constexpr compose_fn compose {};
}

Where I could use to pass it inside std::apply:

template <std::size_t N, typename F>
constexpr auto func_power(F f) {
    auto return_identity_ = [&f]<std::size_t I>(std::integral_constant<std::size_t, I>) noexcept {
        return f;
    };

    auto tup_ = [&]<std::size_t... Is>(std::index_sequence<Is...>) {
        return std::make_tuple(return_identity_(std::integral_constant<std::size_t, Is>{})...);
    }(std::make_index_sequence<N>{});

    /// apply:
    return std::apply(functors::compose, tup_);
}

Whereas the global compose can't be passed because it's ambiguous.

The only thing I could get as general is this one:

[]<typename... Ts>(Ts&&... args){
  return some_overloaded_function(std::forward<Ts>(args)...);
}

However, the following constraints will depend on the some_overloaded_function.

Is there a general way to wrap any overloaded functions into function objects by just implementing 1 tool (function, function object, etc.)?

0 Answers
Related