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 > >