/// \file // Range v3 library // // Copyright Andrey Diduh 2019 // // Use, modification and distribution is subject to the // Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // // Project home: https://github.com/ericniebler/range-v3 // #ifndef RANGE_V3_DETAIL_BIND_BACK_HPP #define RANGE_V3_DETAIL_BIND_BACK_HPP #include #include #include #include #include namespace ranges { // bind_back like std::bind_front has no special treatment for nested // bind-expressions or reference_wrappers; there is no need to wrap // Callables with ranges::protect. namespace detail { template struct bind_back_fn_ { using tuple_t = std::tuple; tuple_t fn_args_; template constexpr auto operator()(CallArgs &&... cargs) && noexcept(is_nothrow_invocable_v) -> invoke_result_t { return tuple_apply( [&](auto && fn, auto &&... args) -> decltype(auto) { return invoke((decltype(fn))fn, (CallArgs &&) cargs..., (decltype(args))args...); }, (std::tuple &&) fn_args_); } /// \overload template constexpr auto operator()(CallArgs &&... cargs) & noexcept(is_nothrow_invocable_v) -> invoke_result_t { return tuple_apply( [&](auto & fn, auto &... args) -> decltype(auto) { return invoke(fn, (CallArgs &&) cargs..., args...); }, fn_args_); } /// \overload template constexpr auto operator()(CallArgs &&... cargs) const & noexcept( is_nothrow_invocable_v) -> invoke_result_t { return tuple_apply( [&](auto & fn, auto &... args) -> decltype(auto) { return invoke(fn, (CallArgs &&) cargs..., args...); }, fn_args_); } }; /// \cond // Unroll a few instantiations to avoid a heavy-weight tuple instantiation template struct bind_back_fn_ { struct tuple_t { Fn fn_; Arg arg_; }; tuple_t fn_args_; template constexpr auto operator()(CallArgs &&... cargs) && noexcept(is_nothrow_invocable_v) -> invoke_result_t { return invoke( (Fn &&) fn_args_.fn_, (CallArgs &&) cargs..., (Arg &&) fn_args_.arg_); } template constexpr auto operator()(CallArgs &&... cargs) & noexcept(is_nothrow_invocable_v) -> invoke_result_t { return invoke(fn_args_.fn_, (CallArgs &&) cargs..., fn_args_.arg_); } template constexpr auto operator()(CallArgs &&... cargs) const & noexcept( is_nothrow_invocable_v) -> invoke_result_t { return invoke(fn_args_.fn_, (CallArgs &&) cargs..., fn_args_.arg_); } }; template struct bind_back_fn_ { struct tuple_t { Fn fn_; Arg0 arg0_; Arg1 arg1_; }; tuple_t fn_args_; template constexpr auto operator()(CallArgs &&... cargs) && noexcept(is_nothrow_invocable_v) -> invoke_result_t { return invoke((Fn &&) fn_args_.fn_, (CallArgs &&) cargs..., (Arg0 &&) fn_args_.arg0_, (Arg1 &&) fn_args_.arg1_); } template constexpr auto operator()(CallArgs &&... cargs) & noexcept(is_nothrow_invocable_v) -> invoke_result_t { return invoke( fn_args_.fn_, (CallArgs &&) cargs..., fn_args_.arg0_, fn_args_.arg1_); } template constexpr auto operator()(CallArgs &&... cargs) const & noexcept( is_nothrow_invocable_v) -> invoke_result_t { return invoke( fn_args_.fn_, (CallArgs &&) cargs..., fn_args_.arg0_, fn_args_.arg1_); } }; /// \endcond template using bind_back_fn = bind_back_fn_, decay_t...>; } // namespace detail struct bind_back_fn { template constexpr auto operator()(Fn && fn, Arg1 && arg1, Args &&... args) const -> detail::bind_back_fn { #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ <= 5 using T = typename detail::bind_back_fn::tuple_t; return {T{(Fn &&) fn, (Arg1 &&) arg1, (Args &&) args...}}; #else return {{(Fn &&) fn, (Arg1 &&) arg1, (Args &&) args...}}; #endif } }; /// \ingroup group-utility /// \sa `bind_back_fn` RANGES_INLINE_VARIABLE(bind_back_fn, bind_back) } // namespace ranges #endif // RANGE_V3_DETAIL_BIND_BACK_HPP