On Thu, 3 Jul 2025 at 23:14, Nathan Myers <n...@cantrip.org> wrote: > > 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 | 94 ++++++++++++++++++++++++++- > 3 files changed, 105 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;
This changes the value for C++17 mode, whereas we want it to be 201603 for C++17/20/23, but 202306 for C++23. So we want two 'values' groups. See how it's done for e.g. shared_ptr_arrays in version.def > }; > }; > @@ -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..d960712480e 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,98 @@ _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> This needs to be _Tp and _Up, not single character names. > + struct __copy_const : conditional<is_const_v<_T>, const _U, _U> {}; Can this be an alias template rather than a new class template? > + > + 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; Is this just __like_t from <bits/move.h> ? > + > + /** 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 > + > #endif // __cpp_lib_bind_front > > #ifdef __cpp_lib_bind_back // C++ >= 23 > -- > 2.50.0 >