#pragma once #include #include #include #if __cpp_lib_bind_front < 202306L or __cpp_lib_bind_back < 202306L #if __cplusplus >= 202002L #include #else #include #endif #endif namespace stdx { inline namespace v1 { template struct with_result_of : F { using R = std::invoke_result_t; // NOLINTNEXTLINE(google-explicit-constructor) constexpr operator R() const noexcept(noexcept(static_cast(*this)())) { return static_cast(*this)(); } // NOLINTNEXTLINE(google-explicit-constructor) constexpr operator R() noexcept(noexcept(static_cast(*this)())) { return static_cast(*this)(); } }; #if __cpp_deduction_guides < 201907L template with_result_of(F) -> with_result_of; #endif namespace detail { #if __cpp_lib_bind_front < 202306L or __cpp_lib_bind_back < 202306L #if __cplusplus >= 202002L template using bind_tuple_t = stdx::tuple; using stdx::get; #else template using bind_tuple_t = std::tuple; using std::get; #endif #endif } // namespace detail #if __cpp_lib_bind_front >= 201907L using std::bind_front; #else namespace detail { template struct bind_front_t; template struct bind_front_t, BoundArgs...> { F f{}; bind_tuple_t t{}; template constexpr auto operator()(Args &&...args) const & { return f(get(t)..., std::forward(args)...); } template constexpr auto operator()(Args &&...args) & { return f(get(t)..., std::forward(args)...); } template constexpr auto operator()(Args &&...args) && { return std::move(f)(get(std::move(t))..., std::forward(args)...); } }; } // namespace detail template constexpr auto bind_front(F &&f, Args &&...args) { return detail::bind_front_t, std::make_index_sequence, std::decay_t...>{ std::forward(f), {std::forward(args)...}}; } #endif #if __cpp_lib_bind_front < 202306L namespace detail { template struct bind_front_value_t; template struct bind_front_value_t, BoundArgs...> { bind_tuple_t t{}; template constexpr auto operator()(Args &&...args) const & { return F(get(t)..., std::forward(args)...); } template constexpr auto operator()(Args &&...args) & { return F(get(t)..., std::forward(args)...); } template constexpr auto operator()(Args &&...args) && { return F(get(std::move(t))..., std::forward(args)...); } }; } // namespace detail template constexpr auto bind_front(Args &&...args) { return detail::bind_front_value_t< F, std::make_index_sequence, std::decay_t...>{ {std::forward(args)...}}; } #endif #if __cpp_lib_bind_back >= 202202L using std::bind_back; #else namespace detail { template struct bind_back_t; template struct bind_back_t, BoundArgs...> { F f{}; bind_tuple_t t{}; template constexpr auto operator()(Args &&...args) const & { return f(std::forward(args)..., get(t)...); } template constexpr auto operator()(Args &&...args) & { return f(std::forward(args)..., get(t)...); } template constexpr auto operator()(Args &&...args) && { return std::move(f)(std::forward(args)..., get(std::move(t))...); } }; } // namespace detail template constexpr auto bind_back(F &&f, Args &&...args) { return detail::bind_back_t, std::make_index_sequence, std::decay_t...>{ std::forward(f), {std::forward(args)...}}; } #endif #if __cpp_lib_bind_back < 202306L namespace detail { template struct bind_back_value_t; template struct bind_back_value_t, BoundArgs...> { bind_tuple_t t{}; template constexpr auto operator()(Args &&...args) const & { return F(std::forward(args)..., get(t)...); } template constexpr auto operator()(Args &&...args) & { return F(std::forward(args)..., get(t)...); } template constexpr auto operator()(Args &&...args) && { return F(std::forward(args)..., get(std::move(t))...); } }; } // namespace detail template constexpr auto bind_back(Args &&...args) { return detail::bind_back_value_t< F, std::make_index_sequence, std::decay_t...>{ {std::forward(args)...}}; } #endif } // namespace v1 } // namespace stdx