Skip to main content
Post Made Community Wiki by 200_success
Source Link

Thanks to the advice I realised it would be a lot easier to implement in C++17 so here is my solution:

namespace detail {
    template <typename Fn, typename... Args>
    struct is_partial_functor_nothrow_constructible {
        enum : bool {
            a = std::is_nothrow_constructible_v<Fn, Fn&&>,
            b = (std::is_nothrow_constructible_v<Args, Args&&> && ...),
            value = a && b
        };
    };

    template <typename Fn, typename... Args>
    constexpr bool is_partial_functor_nothrow_constructible_v =
        is_partial_functor_nothrow_constructible<Fn, Args...>::value;
}

template <typename Fn, typename... Args>
class partial_functor {
private:
    Fn fn_;
    std::tuple<Args...> args_;

public:
    constexpr partial_functor(Fn&& fn, Args&&... args)
        noexcept(detail::is_partial_functor_nothrow_constructible_v<Fn, Args...>)
        : fn_(std::forward<Fn>(fn))
        , args_(std::forward_as_tuple(args...))
    {}

    template <typename... ExArgs>
    constexpr decltype(auto) operator()(ExArgs&&... ex_args)
        noexcept(std::is_nothrow_invocable_v<Fn, Args..., ExArgs...>)
    {
        return std::apply(fn_, std::tuple_cat(
            args_, std::forward_as_tuple(ex_args...)));
    }
};

template <typename Fn, typename... Args>
constexpr decltype(auto) partial(Fn&& fn, Args&&... args)
    noexcept(detail::is_partial_functor_nothrow_constructible_v<Fn, Args...>)
{
    return partial_functor<Fn, Args...>(
        std::forward<Fn>(fn),
        std::forward<Args>(args)...);
}