On Fri, 7 Mar 2025, Tomasz Kamiński wrote:

> Add missing move_constructible && regular_invocable constrains on functor 
> type,
> and is_object on functor result type for invocations of views::zip_transform 
> without range arguments.
> 
>       PR libstdc++/111138
> 
> libstdc++-v3/ChangeLog:
> 
>       * include/std/ranges (_ZipTransform::operator()):
>       Create separate overload for calls with empty range pack,
>       and add move_constructible, regular_invocable and
>       is_object_v<invoke_result_t<...>>> constraints.
>       * testsuite/std/ranges/zip_transform/1.cc: New tests

LGTM

> ---
>  Move the empty-ranges case into separate `operator()`.
>  Add missing `is_object<invoke_result_t<....>>`.
> 
>  Tested on x86_64-linux. OK for trunk?
> 
>  libstdc++-v3/include/std/ranges               | 16 +++++++++-----
>  .../testsuite/std/ranges/zip_transform/1.cc   | 21 +++++++++++++++++++
>  2 files changed, 32 insertions(+), 5 deletions(-)
> 
> diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
> index e21f5284b46..97d22a12dc6 100644
> --- a/libstdc++-v3/include/std/ranges
> +++ b/libstdc++-v3/include/std/ranges
> @@ -5331,15 +5331,21 @@ namespace views::__adaptor
>  
>      struct _ZipTransform
>      {
> +      template<typename _Fp>
> +     requires move_constructible<decay_t<_Fp>> && 
> regular_invocable<decay_t<_Fp>&>
> +       && is_object_v<decay_t<invoke_result_t<decay_t<_Fp>&>>>
> +     constexpr auto
> +     operator() [[nodiscard]] (_Fp&& __f) const
> +     {
> +       return views::empty<decay_t<invoke_result_t<decay_t<_Fp>&>>>;
> +     }
> +
>        template<typename _Fp, typename... _Ts>
> -     requires (sizeof...(_Ts) == 0) || 
> __detail::__can_zip_transform_view<_Fp, _Ts...>
> +     requires (sizeof...(_Ts) != 0) && 
> __detail::__can_zip_transform_view<_Fp, _Ts...>
>       constexpr auto
>       operator() [[nodiscard]] (_Fp&& __f, _Ts&&... __ts) const
>       {
> -       if constexpr (sizeof...(_Ts) == 0)
> -         return views::empty<decay_t<invoke_result_t<decay_t<_Fp>&>>>;
> -       else
> -         return zip_transform_view(std::forward<_Fp>(__f), 
> std::forward<_Ts>(__ts)...);
> +          return zip_transform_view(std::forward<_Fp>(__f), 
> std::forward<_Ts>(__ts)...);
>       }
>      };
>  
> diff --git a/libstdc++-v3/testsuite/std/ranges/zip_transform/1.cc 
> b/libstdc++-v3/testsuite/std/ranges/zip_transform/1.cc
> index 20abdcba0f8..9a0ad3814e6 100644
> --- a/libstdc++-v3/testsuite/std/ranges/zip_transform/1.cc
> +++ b/libstdc++-v3/testsuite/std/ranges/zip_transform/1.cc
> @@ -9,6 +9,23 @@
>  namespace ranges = std::ranges;
>  namespace views = std::views;
>  
> +template<typename T>
> +concept can_zip_transform = requires (T t) {
> +  views::zip_transform(std::forward<T>(t));
> +};
> +
> +static_assert(!can_zip_transform<int>);
> +
> +struct NonMovable {
> +  NonMovable(NonMovable&&) = delete;
> +};
> +
> +static_assert(!can_zip_transform<NonMovable>);
> +static_assert(!can_zip_transform<NonMovable&>);
> +
> +static_assert(!can_zip_transform<void(*)()>);
> +static_assert(can_zip_transform<int(&(*)())[3]>);
> +
>  constexpr bool
>  test01()
>  {
> @@ -46,6 +63,10 @@ test01()
>    VERIFY( ranges::size(z3) == 3 );
>    VERIFY( ranges::equal(z3, (int[]){3, 6, 9}) );
>  
> +  auto z4 = views::zip_transform([] () { return 1; });
> +  VERIFY( ranges::size(z4) == 0 );
> +  static_assert( std::same_as<ranges::range_value_t<decltype(z4)>, int> );
> +
>    return true;
>  }
>  
> -- 
> 2.48.1
> 
> 

Reply via email to