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
>

Reply via email to