This is a snapshot of work on P2714 "Bind front and back to NTTP callables", posted for reference. Not tested.
libstdc++-v3/ChangeLog: PR libstdc++/119744 * include/bits/version.def: Redefine __cpp_lib_bind_front etc. * include/bits/version.h: Ditto. * include/std/functional: Add new bind_front etc. overloads --- libstdc++-v3/include/bits/version.def | 6 +- libstdc++-v3/include/bits/version.h | 18 ++--- libstdc++-v3/include/std/functional | 96 ++++++++++++++++++++++++++- 3 files changed, 107 insertions(+), 13 deletions(-) diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def index b89b287e8e8..f8ccfaeb8c3 100644 --- a/libstdc++-v3/include/bits/version.def +++ b/libstdc++-v3/include/bits/version.def @@ -464,7 +464,7 @@ ftms = { ftms = { name = not_fn; values = { - v = 201603; + v = 202306; cxxmin = 17; }; }; @@ -777,7 +777,7 @@ ftms = { ftms = { name = bind_front; values = { - v = 201907; + v = 202306 cxxmin = 20; }; }; @@ -785,7 +785,7 @@ ftms = { ftms = { name = bind_back; values = { - v = 202202; + v = 202306; cxxmin = 23; extra_cond = "__cpp_explicit_this_parameter"; }; diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h index a70a7ede68c..52e6ae2d9b8 100644 --- a/libstdc++-v3/include/bits/version.h +++ b/libstdc++-v3/include/bits/version.h @@ -511,10 +511,10 @@ #undef __glibcxx_want_make_from_tuple #if !defined(__cpp_lib_not_fn) -# if (__cplusplus >= 201703L) -# define __glibcxx_not_fn 201603L +# if (__cplusplus >= 202306L) +# define __glibcxx_not_fn 202306L # if defined(__glibcxx_want_all) || defined(__glibcxx_want_not_fn) -# define __cpp_lib_not_fn 201603L +# define __cpp_lib_not_fn 202306L # endif # endif #endif /* !defined(__cpp_lib_not_fn) && defined(__glibcxx_want_not_fn) */ @@ -866,20 +866,20 @@ #undef __glibcxx_want_atomic_value_initialization #if !defined(__cpp_lib_bind_front) -# if (__cplusplus >= 202002L) -# define __glibcxx_bind_front 201907L +# if (__cplusplus >= 202306L) +# define __glibcxx_bind_front 202306L # if defined(__glibcxx_want_all) || defined(__glibcxx_want_bind_front) -# define __cpp_lib_bind_front 201907L +# define __cpp_lib_bind_front 202306L # endif # endif #endif /* !defined(__cpp_lib_bind_front) && defined(__glibcxx_want_bind_front) */ #undef __glibcxx_want_bind_front #if !defined(__cpp_lib_bind_back) -# if (__cplusplus >= 202100L) && (__cpp_explicit_this_parameter) -# define __glibcxx_bind_back 202202L +# if (__cplusplus >= 202306L) && (__cpp_explicit_this_parameter) +# define __glibcxx_bind_back 202306L # if defined(__glibcxx_want_all) || defined(__glibcxx_want_bind_back) -# define __cpp_lib_bind_back 202202L +# define __cpp_lib_bind_back 202306L # endif # endif #endif /* !defined(__cpp_lib_bind_back) && defined(__glibcxx_want_bind_back) */ diff --git a/libstdc++-v3/include/std/functional b/libstdc++-v3/include/std/functional index 307bcb95bcc..c317d471350 100644 --- a/libstdc++-v3/include/std/functional +++ b/libstdc++-v3/include/std/functional @@ -940,7 +940,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_bound_args(std::forward<_Args>(__args)...) { static_assert(sizeof...(_Args) == sizeof...(_BoundArgs)); } -#if __cpp_explicit_this_parameter +#ifdef __cpp_explicit_this_parameter template<typename _Self, typename... _CallArgs> constexpr invoke_result_t<__like_t<_Self, _Fd>, __like_t<_Self, _BoundArgs>..., _CallArgs...> @@ -1049,6 +1049,97 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return _Bind_front_t<_Fn, _Args...>(0, std::forward<_Fn>(__fn), std::forward<_Args>(__args)...); } + +#if __cpp_lib_bind_front >= 202306 + + template<typename _T, typename _U> + struct __copy_const : conditional<is_const_v<_T>, const _U, _U> {}; + + template<typename _T, typename _U, + class _X = __copy_const<remove_reference_t<_T>, _U>::type> + + struct __copy_value_category + : conditional<is_lvalue_reference_v<_T&&>, _X&, _X&&> + {}; + + template<typename _T, typename _U> + struct __type_forward_like : __copy_value_category<_T, remove_reference_t<_U>> + {}; + + template<typename _T, typename _U> + using __type_forward_like_t = __type_forward_like<_T, _U>::type; + + /** Create call wrapper by partial application of arguments to function. + * + * The result of `std::bind_front<f>(args...)` is a function object that + * stores `f` and the bound arguments, `args...`. When that function + * object is invoked with `call_args...` it returns the result of calling + * `f(args..., call_args...)`. + * + * @since C++26 + */ + + template<auto __fn, typename... _Args> + constexpr auto + bind_front(_Args&&... __args) + requires ( + (is_constructible_v<decay_t<_Args>, _Args> and ...) and + (is_move_constructible_v<decay_t<_Args>> and ...)) + { + using _Fn = decltype(__fn); + if constexpr (is_pointer_v<_Fn> or is_member_pointer_v<_Fn>) { + static_assert(__fn != nullptr); + } + return [... __bound_args(std::forward<_Args>(__args))]< + typename _Self, typename... _T> + (this _Self&&, _T&&... __call_args) + noexcept(is_nothrow_invocable_v< + _Fn, __type_forward_like_t<_Self, decay_t<_Args>>..., _T...>) + -> invoke_result_t< + _Fn, __type_forward_like_t<_Self, decay_t<_Args>>..., _T...> + { + return invoke(__fn, + forward_like<_Self>(__bound_args)..., + forward<_T>(__call_args)...); + }; + } + + /** Create call wrapper by partial application of arguments to function. + * + * The result of `std::bind_back<f>(args...)` is a function object that + * stores `f` and the bound arguments, `args...`. When that function + * object is invoked with `call_args...` it returns the result of calling + * `f(call_args..., args...)`. + * + * @since C++26 + */ + + template<auto __fn, typename... _Args> + constexpr auto + bind_back(_Args&&... __args) + requires ( + (is_constructible_v<decay_t<_Args>, _Args> and ...) and + (is_move_constructible_v<decay_t<_Args>> and ...)) + { + using _Fn = decltype(__fn); + if constexpr (is_pointer_v<_Fn> or is_member_pointer_v<_Fn>) { + static_assert(__fn != nullptr); + } + return [... __bound_args(std::forward<_Args>(__args))]< + typename _Self, typename... _T> + (this _Self&&, _T&&... __call_args) + noexcept(is_nothrow_invocable_v< + _Fn, __type_forward_like_t<_Self, decay_t<_Args>>..., _T...>) + -> invoke_result_t< + _Fn, __type_forward_like_t<_Self, decay_t<_Args>>..., _T...> + { + return invoke(__fn, + forward<_T>(__call_args)..., + forward_like<_Self>(__bound_args)...); + }; + } + +#endif // __cpp_lib_bind_front >= 202306, NTTP bind_front #endif // __cpp_lib_bind_front #ifdef __cpp_lib_bind_back // C++ >= 23 @@ -1216,6 +1307,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION not_fn(_Fn&& __fn) noexcept(std::is_nothrow_constructible<std::decay_t<_Fn>, _Fn&&>::value) { + if constexpr (is_pointer_v<_Fn> || is_member_pointer_v<_Fn>) { + static_assert(__fn != nullptr); + } return _Not_fn<std::decay_t<_Fn>>{std::forward<_Fn>(__fn), 0}; } #endif -- 2.50.0