We might also need is_default_constructible_v.
For example, a singleton satisfies is_empty_v<F> && copyable<F> &&
trivially_copyable<F>, but it is not a default-constructible.
Otherwise, the forward iterator will not be default-constructible and will
no longer be a forward iterator.
I personally think that determining the condition for storing functors
inside iterators is actually difficult.


Tomasz Kaminski <[email protected]> 於 2025年11月15日 週六 上午1:37寫道:

> From other side, it would be fairly easy to add another _TrivlalEmpty
> specialization for __func_handle,
> that would be generated under p3117r1 conditions, which I do not like, as
> they do not make even *it
> on same iterator sable for the Obfuscating symbol.
> I would go instead with is_empty_v<F> && copyable<F> &&
> trivially_copyable<F>, and have [[no_unique_address]] F _M_fun
> member.
>
> From that perspective, think we should land this patch regardless. Even if
> we would like to do a follow up aligned with
> additional specialization that is aligned the paper.
>
>
> Regards,
> Tomasz
>
> On Fri, Nov 14, 2025 at 3:37 PM Tomasz Kaminski <[email protected]>
> wrote:
>
>>
>>
>> On Fri, Nov 14, 2025 at 2:18 PM Hewill Kang <[email protected]> wrote:
>>
>>> I can't help but wonder, if this patch can't optimize for lambdas (users
>>> generally don't explicitly spell `static`), then I don't see much point in
>>> this optimization.
>>>
>> Then they should start to. if they want to get optimizations. For most
>> cases it really does not matter, as the compiler inlines and removes all
>> iterators.
>> The only relevant cases here are erasing view (storing in any_view) or
>> relying on range being borrowed.
>>
>>>
>>> I think the case of `Obfuscate` is unlikely to occur. The view class
>>> will move the original object to the `movable_box` via `std::move(fun)`, so
>>> `this` pointer has already changed.
>>>
>> I believe the standard requires it to work, so breaking it would be
>> invalid optimization.
>>
>>>
>>> If we could actually create such a pretentious functor with a disgusting
>>> operator(), I think the standard has every reason not to care about it.
>>>
>>> Therefore, after thinking about it, I think we should perhaps follow
>>> p3117r1 and use `is_empty_v<F> && is_trivially_default_constructible_v<F
>>> > && is_trivially_destructible_v<F>` to optimize lambda. Because that
>>> is undoubtedly the most common use case (and the most worthy of
>>> optimization). This is something this patch should be interested in.
>>>
>> Unless the standard gives permission to do so, I do not think such change
>> is possible.
>>
>>>
>>> Tomasz Kaminski <[email protected]> 於 2025年11月14日 週五 下午5:36寫道:
>>>
>>>>
>>>>
>>>> On Fri, Nov 14, 2025 at 10:24 AM Hewill Kang <[email protected]> wrote:
>>>>
>>>>> Yes, I do not think anything in standard clearly states the that
>>>>>> following is
>>>>>> allowed to fail:
>>>>>> struct Obfuscate
>>>>>> {
>>>>>>   int operator()(int x) const
>>>>>>   { return x + static_assert<unintptr_t>(this); }
>>>>>> };
>>>>>
>>>>>
>>>>>> std::vector<int> v{1, 2, 3, 4, 5};
>>>>>> auto tv = v | std::transform(Obfuscate{});
>>>>>> VERIFY( ranges::equal(tv, tv) );
>>>>>> But storing an empty object in an iterator will break.
>>>>>
>>>>>
>>>>> This is a very good observation, so recreating empty objects is still
>>>>> problematic.
>>>>> It also seems to suggest that
>>>>> https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3117r1.html 
>>>>> (most
>>>>> likely a follow-up to this patch) and
>>>>> https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3705r1.html
>>>>> might have issues with this.
>>>>> For example, `operator()` uses `this` or `operator==` uses `this`.
>>>>>
>>>> Yes, static operator() is bulletproof way of ensuring that it does not
>>>> depend on object identity,
>>>> even if the object itself is not empty. We do not need to use
>>>> heuristics based on size anymore.
>>>>
>>>>>
>>>>> Tomasz Kaminski <[email protected]> 於 2025年11月14日 週五 下午2:36寫道:
>>>>>
>>>>>>
>>>>>>
>>>>>> On Fri, Nov 14, 2025 at 4:16 AM Patrick Palka <[email protected]>
>>>>>> wrote:
>>>>>>
>>>>>>> On Thu, 13 Nov 2025, Tomasz Kamiński wrote:
>>>>>>>
>>>>>>> > The iterators for transform views (views::transform,
>>>>>>> views::zip_transform,
>>>>>>> > and views::adjacent_transform) now store a __detail::__func_handle
>>>>>>> instead
>>>>>>> > of a pointer to the view object (_M_parent).
>>>>>>> >
>>>>>>> > The behavior of the __func_handle specialization depends on the
>>>>>>> _FunctorType
>>>>>>> > template parameter:
>>>>>>> > * _FunctionPtr: Used if the functor is a function pointer. The
>>>>>>> pointer is
>>>>>>> >   stored directly in __func_handle and the iterator, avoiding
>>>>>>> double
>>>>>>> >   indirection through a pointer to the function pointer.
>>>>>>> > * _MemberPointer: Used for data or function member pointers. This
>>>>>>> behaves
>>>>>>> >   similarly to _FunctionPtr, but uses __invoke for invocations.
>>>>>>> > * _StaticOperator: Used if the operator() selected by overload
>>>>>>> resolution
>>>>>>> >   for the   iterator reference is static. In this case,
>>>>>>> __func_handle is empty,
>>>>>>> >   reducing the iterator size.
>>>>>>> > * _Statefull: Used for all remaining cases. __func_handle stores a
>>>>>>> pointer
>>>>>>> >   to the functor object stored within the view. Only for this
>>>>>>> specialization is
>>>>>>> >   the  cv-qualification of the functor template parameter (_Fn)
>>>>>>> relevant, and
>>>>>>> >   both const and mutable specializations are generated.
>>>>>>>
>>>>>>> FWIW it's spelled 'stateful' with just one l.
>>>>>>>
>>>>>>> I guess you concluded that this optimization is unsafe for empty
>>>>>>> objects
>>>>>>> with non-static operator()?
>>>>>>>
>>>>>> Yes, I do not think anything in standard clearly states the that
>>>>>> following is
>>>>>> allowed to fail:
>>>>>> struct Obfuscate
>>>>>> {
>>>>>>   int operator()(int x) const
>>>>>>   { return x + static_assert<unintptr_t>(this); }
>>>>>> };
>>>>>>
>>>>>> std::vector<int> v{1, 2, 3, 4, 5};
>>>>>> auto tv = v | std::transform(Obfuscate{});
>>>>>> VERIFY( ranges::equal(tv, tv) );
>>>>>>
>>>>>> But storing an empty object in an iterator will break.
>>>>>>
>>>>>>
>>>>>>> >
>>>>>>> > As a consequence of these changes, the iterators of transform
>>>>>>> views no longer
>>>>>>> > depend on the view object when __func_handle is specialized for
>>>>>>> values other
>>>>>>> > than _Statefull. The corresponding views are not marked as
>>>>>>> borrowed_range,
>>>>>>> > as they are not marked as such in the standard.
>>>>>>> >
>>>>>>> > Storing function member pointers directly increases the iterator
>>>>>>> size in that
>>>>>>> > specific case, but this is deemed beneficial for consistent
>>>>>>> treatment of
>>>>>>> > function and data member pointers.
>>>>>>> >
>>>>>>> > To avoid materializing temporaries when the underlying iterator(s)
>>>>>>> return a
>>>>>>> > prvalue, the _M_call_deref and _M_call_subscript methods of
>>>>>>> __func_handle are
>>>>>>> > defined to accept the iterator(s), which are then dereferenced as
>>>>>>> arguments
>>>>>>> > of the functor.
>>>>>>> >
>>>>>>> > Using _Fd::operator()(*__iters...) inside requires expression is
>>>>>>> only
>>>>>>> > supported since clang-20, however at the point of GCC-16 release,
>>>>>>> clang-22
>>>>>>> > should be already available.
>>>>>>> >
>>>>>>> > libstdc++-v3/ChangeLog:
>>>>>>> >
>>>>>>> >       * include/std/ranges (__detail::__func_handle)
>>>>>>> >       (__detail::func_handle_t): Define.
>>>>>>> >       (transform_view::_Iterator, zip_transform_view::_Iterator)
>>>>>>> >       (adjacent_tranform_view::_Iterator): Replace pointer to view
>>>>>>> >       (_M_parent) with pointer to functor (_M_fun). Update
>>>>>>> constructors
>>>>>>> >       to cosntruct _M_fun from *__parent->_M_fun. Define operator*
>>>>>>> and
>>>>>>> >       operator[] in terms of _M_call_deref and _M_call_subscript.
>>>>>>> >       * testsuite/std/ranges/adaptors/adjacent_transform/1.cc: New
>>>>>>> tests.
>>>>>>> >       * testsuite/std/ranges/adaptors/transform.cc: New tests.
>>>>>>> >       * testsuite/std/ranges/zip_transform/1.cc: New tests.
>>>>>>> > ---
>>>>>>> > Tested transform view files locally. More testing in progress.
>>>>>>> >
>>>>>>> >  libstdc++-v3/include/std/ranges               | 214
>>>>>>> +++++++++++++++---
>>>>>>> >  .../ranges/adaptors/adjacent_transform/1.cc   |  97 ++++++++
>>>>>>> >  .../std/ranges/adaptors/transform.cc          | 118 +++++++++-
>>>>>>> >  .../testsuite/std/ranges/zip_transform/1.cc   | 101 +++++++++
>>>>>>> >  4 files changed, 493 insertions(+), 37 deletions(-)
>>>>>>> >
>>>>>>> > diff --git a/libstdc++-v3/include/std/ranges
>>>>>>> b/libstdc++-v3/include/std/ranges
>>>>>>> > index ae57b9a0809..28b4f1d2b90 100644
>>>>>>> > --- a/libstdc++-v3/include/std/ranges
>>>>>>> > +++ b/libstdc++-v3/include/std/ranges
>>>>>>> > @@ -286,6 +286,138 @@ namespace ranges
>>>>>>> >       operator->() const noexcept
>>>>>>> >       { return std::__addressof(_M_value); }
>>>>>>> >        };
>>>>>>> > +
>>>>>>> > +      enum class _FunctorType
>>>>>>> > +      {
>>>>>>> > +     _FunctionPtr,
>>>>>>> > +     _MemberPtr,
>>>>>>> > +     _StaticOperator,
>>>>>>> > +     _Statefull,
>>>>>>> > +      };
>>>>>>> > +
>>>>>>> > +      template<typename _Fn, _FunctorType __ft>
>>>>>>> > +      struct __func_handle
>>>>>>> > +      {
>>>>>>> > +     __func_handle() = default;
>>>>>>> > +
>>>>>>> > +     constexpr explicit
>>>>>>> > +     __func_handle(_Fn& __func) noexcept
>>>>>>> > +     : _M_ptr(std::addressof(__func))
>>>>>>> > +     { }
>>>>>>> > +
>>>>>>> > +     template<typename _Un>
>>>>>>> > +       requires (!is_const_v<_Un>) && is_same_v<const _Un, _Fn>
>>>>>>> > +       constexpr explicit
>>>>>>> > +       __func_handle(__func_handle<_Un, __ft> __other) noexcept
>>>>>>> > +       : _M_ptr(__other._M_ptr)
>>>>>>> > +       { }
>>>>>>> > +
>>>>>>> > +     template<typename... _Iters>
>>>>>>> > +       constexpr decltype(auto)
>>>>>>> > +       _M_call_deref(const _Iters&... __iters) const
>>>>>>> > +       noexcept(noexcept((*_M_ptr)(*__iters...)))
>>>>>>> > +       { return (*_M_ptr)(*__iters...); }
>>>>>>> > +
>>>>>>> > +     template<typename _DistType, typename... _Iters>
>>>>>>> > +       constexpr decltype(auto)
>>>>>>> > +       _M_call_subscript(const _DistType __n, const _Iters&...
>>>>>>> __iters) const
>>>>>>> > +
>>>>>>>  
>>>>>>> noexcept(noexcept((*_M_ptr)(__iters[iter_difference_t<_Iters>(__n)]...)))
>>>>>>> > +       { return
>>>>>>> (*_M_ptr)(__iters[iter_difference_t<_Iters>(__n)]...); }
>>>>>>> > +
>>>>>>> > +      private:
>>>>>>> > +     _Fn* _M_ptr = nullptr;
>>>>>>> > +
>>>>>>> > +     template<typename, _FunctorType>
>>>>>>> > +       friend struct __func_handle;
>>>>>>> > +      };
>>>>>>> > +
>>>>>>> > +      template<typename _Fn>
>>>>>>> > +      struct __func_handle<_Fn, _FunctorType::_FunctionPtr>
>>>>>>> > +      {
>>>>>>> > +     __func_handle() = default;
>>>>>>> > +
>>>>>>> > +     constexpr explicit
>>>>>>> > +     __func_handle(_Fn __func) noexcept
>>>>>>> > +     : _M_ptr(__func)
>>>>>>> > +     { }
>>>>>>> > +
>>>>>>> > +     template<typename... _Iters>
>>>>>>> > +       constexpr decltype(auto)
>>>>>>> > +       _M_call_deref(const _Iters&... __iters) const
>>>>>>> > +       noexcept(noexcept(_M_ptr(*__iters...)))
>>>>>>> > +       { return _M_ptr(*__iters...); }
>>>>>>> > +
>>>>>>> > +     template<typename _DistType, typename... _Iters>
>>>>>>> > +       constexpr decltype(auto)
>>>>>>> > +       _M_call_subscript(const _DistType __n, const _Iters&...
>>>>>>> __iters) const
>>>>>>> > +
>>>>>>>  noexcept(noexcept(_M_ptr(__iters[iter_difference_t<_Iters>(__n)]...)))
>>>>>>> > +       { return
>>>>>>> _M_ptr(__iters[iter_difference_t<_Iters>(__n)]...); }
>>>>>>> > +
>>>>>>> > +      private:
>>>>>>> > +     _Fn _M_ptr = nullptr;
>>>>>>> > +      };
>>>>>>> > +
>>>>>>> > +      template<typename _Fn>
>>>>>>> > +      struct __func_handle<_Fn, _FunctorType::_MemberPtr>
>>>>>>> > +      {
>>>>>>> > +     __func_handle() = default;
>>>>>>> > +
>>>>>>> > +     constexpr explicit
>>>>>>> > +     __func_handle(_Fn __func) noexcept
>>>>>>> > +     : _M_ptr(__func)
>>>>>>> > +     {}
>>>>>>> > +
>>>>>>> > +     template<typename... _Iters>
>>>>>>> > +     constexpr decltype(auto)
>>>>>>> > +       _M_call_deref(const _Iters&... __iters) const
>>>>>>> > +       noexcept(noexcept(std::__invoke(_M_ptr, *__iters...)))
>>>>>>> > +       { return std::__invoke(_M_ptr, *__iters...); }
>>>>>>> > +
>>>>>>> > +     template<typename _DistType, typename... _Iters>
>>>>>>> > +       constexpr decltype(auto)
>>>>>>> > +       _M_call_subscript(const _DistType __n, const _Iters&...
>>>>>>> __iters) const
>>>>>>> > +       noexcept(noexcept(std::__invoke(_M_ptr,
>>>>>>> __iters[iter_difference_t<_Iters>(__n)]...)))
>>>>>>> > +       { return std::__invoke(_M_ptr,
>>>>>>> __iters[iter_difference_t<_Iters>(__n)]...); }
>>>>>>> > +
>>>>>>> > +      private:
>>>>>>> > +     _Fn _M_ptr = nullptr;
>>>>>>> > +      };
>>>>>>> > +
>>>>>>> > +      template<typename _Fn>
>>>>>>> > +      struct __func_handle<_Fn, _FunctorType::_StaticOperator>
>>>>>>> > +      {
>>>>>>> > +     __func_handle() = default;
>>>>>>> > +
>>>>>>> > +     constexpr explicit
>>>>>>> > +     __func_handle(const _Fn&) noexcept
>>>>>>> > +     {}
>>>>>>> > +
>>>>>>> > +     template<typename... _Iters>
>>>>>>> > +      static constexpr decltype(auto)
>>>>>>> > +       _M_call_deref(const _Iters&... __iters)
>>>>>>> > +       noexcept(noexcept(_Fn::operator()(*__iters...)))
>>>>>>> > +       { return _Fn::operator()(*__iters...); }
>>>>>>> > +
>>>>>>> > +     template<typename _DistType, typename... _Iters>
>>>>>>> > +       static constexpr decltype(auto)
>>>>>>> > +       _M_call_subscript(_DistType __n, const _Iters&... __iters)
>>>>>>> > +
>>>>>>>  
>>>>>>> noexcept(noexcept(_Fn::operator()(__iters[iter_difference_t<_Iters>(__n)]...)))
>>>>>>> > +       { return
>>>>>>> _Fn::operator()(__iters[iter_difference_t<_Iters>(__n)]...); }
>>>>>>> > +      };
>>>>>>> > +
>>>>>>> > +      template<typename _Fn, typename... _Iters>
>>>>>>> > +     using __func_handle_t = decltype([] {
>>>>>>> > +       using _Fd = remove_cv_t<_Fn>;
>>>>>>> > +       if constexpr (is_member_pointer_v<_Fd>)
>>>>>>> > +         return __func_handle<_Fd, _FunctorType::_MemberPtr>();
>>>>>>> > +       else if constexpr
>>>>>>> (std::is_function_v<remove_pointer_t<_Fd>>)
>>>>>>> > +         return __func_handle<_Fd, _FunctorType::_FunctionPtr>();
>>>>>>> > +       else if constexpr (requires (const _Iters&... __iters)
>>>>>>> > +                            { _Fd::operator()(*__iters...); })
>>>>>>> > +         return __func_handle<_Fd,
>>>>>>> _FunctorType::_StaticOperator>();
>>>>>>> > +       else
>>>>>>> > +         return __func_handle<_Fn, _FunctorType::_Statefull>();
>>>>>>> > +     }());
>>>>>>> >    } // namespace __detail
>>>>>>> >
>>>>>>> >    /// A view that contains exactly one element.
>>>>>>> > @@ -1874,6 +2006,10 @@ namespace views::__adaptor
>>>>>>> >       private:
>>>>>>> >         using _Parent = __detail::__maybe_const_t<_Const,
>>>>>>> transform_view>;
>>>>>>> >         using _Base = transform_view::_Base<_Const>;
>>>>>>> > +       using _Base_iter = iterator_t<_Base>;
>>>>>>> > +       using _Func_handle = __detail::__func_handle_t<
>>>>>>> > +                              __detail::__maybe_const_t<_Const,
>>>>>>> _Fp>,
>>>>>>> > +                              _Base_iter>;
>>>>>>> >
>>>>>>> >         static auto
>>>>>>> >         _S_iter_concept()
>>>>>>> > @@ -1888,10 +2024,8 @@ namespace views::__adaptor
>>>>>>> >             return input_iterator_tag{};
>>>>>>> >         }
>>>>>>> >
>>>>>>> > -       using _Base_iter = iterator_t<_Base>;
>>>>>>> > -
>>>>>>> >         _Base_iter _M_current = _Base_iter();
>>>>>>> > -       _Parent* _M_parent = nullptr;
>>>>>>> > +       [[no_unique_address]] _Func_handle _M_fun;
>>>>>>> >
>>>>>>> >       public:
>>>>>>> >         using iterator_concept = decltype(_S_iter_concept());
>>>>>>> > @@ -1904,16 +2038,20 @@ namespace views::__adaptor
>>>>>>> >         _Iterator() requires default_initializable<_Base_iter> =
>>>>>>> default;
>>>>>>> >
>>>>>>> >         constexpr
>>>>>>> > -       _Iterator(_Parent* __parent, _Base_iter __current)
>>>>>>> > -         : _M_current(std::move(__current)),
>>>>>>> > -           _M_parent(__parent)
>>>>>>> > +       _Iterator(_Func_handle __fun, _Base_iter __current)
>>>>>>> > +         : _M_current(std::move(__current)), _M_fun(__fun)
>>>>>>> >         { }
>>>>>>> >
>>>>>>> > +       constexpr
>>>>>>> > +       _Iterator(_Parent* __parent, _Base_iter __current)
>>>>>>> > +         : _M_current(std::move(__current)),
>>>>>>> _M_fun(*__parent->_M_fun)
>>>>>>> > +       {}
>>>>>>> > +
>>>>>>> >         constexpr
>>>>>>> >         _Iterator(_Iterator<!_Const> __i)
>>>>>>> >           requires _Const
>>>>>>> >             && convertible_to<iterator_t<_Vp>, _Base_iter>
>>>>>>> > -         : _M_current(std::move(__i._M_current)),
>>>>>>> _M_parent(__i._M_parent)
>>>>>>> > +         : _M_current(std::move(__i._M_current)),
>>>>>>> _M_fun(__i._M_fun)
>>>>>>> >         { }
>>>>>>> >
>>>>>>> >         constexpr const _Base_iter&
>>>>>>> > @@ -1926,8 +2064,8 @@ namespace views::__adaptor
>>>>>>> >
>>>>>>> >         constexpr decltype(auto)
>>>>>>> >         operator*() const
>>>>>>> > -         noexcept(noexcept(std::__invoke(*_M_parent->_M_fun,
>>>>>>> *_M_current)))
>>>>>>> > -       { return std::__invoke(*_M_parent->_M_fun, *_M_current); }
>>>>>>> > +         noexcept(noexcept(_M_fun._M_call_deref(_M_current)))
>>>>>>> > +       { return _M_fun._M_call_deref(_M_current); }
>>>>>>> >
>>>>>>> >         constexpr _Iterator&
>>>>>>> >         operator++()
>>>>>>> > @@ -1980,7 +2118,7 @@ namespace views::__adaptor
>>>>>>> >         constexpr decltype(auto)
>>>>>>> >         operator[](difference_type __n) const
>>>>>>> >           requires random_access_range<_Base>
>>>>>>> > -       { return std::__invoke(*_M_parent->_M_fun,
>>>>>>> _M_current[__n]); }
>>>>>>> > +       { return _M_fun._M_call_subscript(__n, _M_current); }
>>>>>>> >
>>>>>>> >         friend constexpr bool
>>>>>>> >         operator==(const _Iterator& __x, const _Iterator& __y)
>>>>>>> > @@ -2018,17 +2156,17 @@ namespace views::__adaptor
>>>>>>> >         friend constexpr _Iterator
>>>>>>> >         operator+(_Iterator __i, difference_type __n)
>>>>>>> >           requires random_access_range<_Base>
>>>>>>> > -       { return {__i._M_parent, __i._M_current + __n}; }
>>>>>>> > +       { return {__i._M_fun, __i._M_current + __n}; }
>>>>>>> >
>>>>>>> >         friend constexpr _Iterator
>>>>>>> >         operator+(difference_type __n, _Iterator __i)
>>>>>>> >           requires random_access_range<_Base>
>>>>>>> > -       { return {__i._M_parent, __i._M_current + __n}; }
>>>>>>> > +       { return {__i._M_fun, __i._M_current + __n}; }
>>>>>>> >
>>>>>>> >         friend constexpr _Iterator
>>>>>>> >         operator-(_Iterator __i, difference_type __n)
>>>>>>> >           requires random_access_range<_Base>
>>>>>>> > -       { return {__i._M_parent, __i._M_current - __n}; }
>>>>>>> > +       { return {__i._M_fun, __i._M_current - __n}; }
>>>>>>> >
>>>>>>> >         // _GLIBCXX_RESOLVE_LIB_DEFECTS
>>>>>>> >         // 3483. transform_view::iterator's difference is
>>>>>>> overconstrained
>>>>>>> > @@ -5126,13 +5264,21 @@ namespace views::__adaptor
>>>>>>> >    class zip_transform_view<_Fp, _Vs...>::_Iterator : public
>>>>>>> __iter_cat<_Const>
>>>>>>> >    {
>>>>>>> >      using _Parent = __detail::__maybe_const_t<_Const,
>>>>>>> zip_transform_view>;
>>>>>>> > +    using _Fun_handle = __detail::__func_handle_t<
>>>>>>> > +                       __detail::__maybe_const_t<_Const, _Fp>,
>>>>>>> > +
>>>>>>>  iterator_t<__detail::__maybe_const_t<_Const, _Vs>>...>;
>>>>>>> >
>>>>>>> > -    _Parent* _M_parent = nullptr;
>>>>>>> > +    [[no_unique_address]] _Fun_handle _M_fun;
>>>>>>> >      __ziperator<_Const> _M_inner;
>>>>>>> >
>>>>>>> > +    constexpr
>>>>>>> > +    _Iterator(_Fun_handle __fun, __ziperator<_Const> __inner)
>>>>>>> > +      : _M_fun(__fun), _M_inner(std::move(__inner))
>>>>>>> > +    { }
>>>>>>> > +
>>>>>>> >      constexpr
>>>>>>> >      _Iterator(_Parent& __parent, __ziperator<_Const> __inner)
>>>>>>> > -      : _M_parent(std::__addressof(__parent)),
>>>>>>> _M_inner(std::move(__inner))
>>>>>>> > +      : _M_fun(*__parent._M_fun), _M_inner(std::move(__inner))
>>>>>>> >      { }
>>>>>>> >
>>>>>>> >      friend class zip_transform_view;
>>>>>>> > @@ -5150,14 +5296,14 @@ namespace views::__adaptor
>>>>>>> >      constexpr
>>>>>>> >      _Iterator(_Iterator<!_Const> __i)
>>>>>>> >        requires _Const && convertible_to<__ziperator<false>,
>>>>>>> __ziperator<_Const>>
>>>>>>> > -      : _M_parent(__i._M_parent),
>>>>>>> _M_inner(std::move(__i._M_inner))
>>>>>>> > +      : _M_fun(__i._M_fun), _M_inner(std::move(__i._M_inner))
>>>>>>> >      { }
>>>>>>> >
>>>>>>> >      constexpr decltype(auto)
>>>>>>> >      operator*() const
>>>>>>> >      {
>>>>>>> >        return std::apply([&](const auto&... __iters) ->
>>>>>>> decltype(auto) {
>>>>>>> > -        return std::__invoke(*_M_parent->_M_fun, *__iters...);
>>>>>>> > +     return _M_fun._M_call_deref(__iters...);
>>>>>>> >        }, _M_inner._M_current);
>>>>>>> >      }
>>>>>>> >
>>>>>>> > @@ -5213,7 +5359,7 @@ namespace views::__adaptor
>>>>>>> >      operator[](difference_type __n) const requires
>>>>>>> random_access_range<_Base<_Const>>
>>>>>>> >      {
>>>>>>> >        return std::apply([&]<typename... _Is>(const _Is&...
>>>>>>> __iters) -> decltype(auto) {
>>>>>>> > -        return std::__invoke(*_M_parent->_M_fun,
>>>>>>> __iters[iter_difference_t<_Is>(__n)]...);
>>>>>>> > +     return _M_fun._M_call_subscript(__n, __iters...);
>>>>>>> >        }, _M_inner._M_current);
>>>>>>> >      }
>>>>>>> >
>>>>>>> > @@ -5230,17 +5376,17 @@ namespace views::__adaptor
>>>>>>> >      friend constexpr _Iterator
>>>>>>> >      operator+(const _Iterator& __i, difference_type __n)
>>>>>>> >        requires random_access_range<_Base<_Const>>
>>>>>>> > -    { return _Iterator(*__i._M_parent, __i._M_inner + __n); }
>>>>>>> > +    { return _Iterator(__i._M_fun, __i._M_inner + __n); }
>>>>>>> >
>>>>>>> >      friend constexpr _Iterator
>>>>>>> >      operator+(difference_type __n, const _Iterator& __i)
>>>>>>> >        requires random_access_range<_Base<_Const>>
>>>>>>> > -    { return _Iterator(*__i._M_parent, __i._M_inner + __n); }
>>>>>>> > +    { return _Iterator(__i._M_fun, __i._M_inner + __n); }
>>>>>>> >
>>>>>>> >      friend constexpr _Iterator
>>>>>>> >      operator-(const _Iterator& __i, difference_type __n)
>>>>>>> >        requires random_access_range<_Base<_Const>>
>>>>>>> > -    { return _Iterator(*__i._M_parent, __i._M_inner - __n); }
>>>>>>> > +    { return _Iterator(__i._M_fun, __i._M_inner - __n); }
>>>>>>> >
>>>>>>> >      friend constexpr difference_type
>>>>>>> >      operator-(const _Iterator& __x, const _Iterator& __y)
>>>>>>> > @@ -5807,13 +5953,23 @@ namespace views::__adaptor
>>>>>>> >    {
>>>>>>> >      using _Parent = __detail::__maybe_const_t<_Const,
>>>>>>> adjacent_transform_view>;
>>>>>>> >      using _Base = __detail::__maybe_const_t<_Const, _Vp>;
>>>>>>> > +    using _Fun_handle = decltype([]<size_t...
>>>>>>> _Ids>(std::index_sequence<_Ids...>) {
>>>>>>> > +                        return __detail::__func_handle_t<
>>>>>>> > +
>>>>>>>  __detail::__maybe_const_t<_Const, _Fp>,
>>>>>>> > +
>>>>>>>  iterator_t<__detail::__maybe_const_t<_Const || (_Ids < 0u), 
>>>>>>> _Vp>>...>();
>>>>>>>
>>>>>>> Maybe '(_Ids, _Const)' would be a little less cryptic than
>>>>>>> '_Const || (_Ids < 0u)'?
>>>>>>>
>>>>>> Yes,  that is major improvement.
>>>>>>
>>>>>>> Besides that looks good!
>>>>>>>
>>>>>>> > +                     }(make_index_sequence<_Nm>()));
>>>>>>> >
>>>>>>> > -    _Parent* _M_parent = nullptr;
>>>>>>> > +    [[no_unique_address]] _Fun_handle _M_fun;
>>>>>>> >      _InnerIter<_Const> _M_inner;
>>>>>>> >
>>>>>>> > +    constexpr
>>>>>>> > +    _Iterator(_Fun_handle __fun, _InnerIter<_Const> __inner)
>>>>>>> > +      : _M_fun(__fun), _M_inner(std::move(__inner))
>>>>>>> > +    { }
>>>>>>> > +
>>>>>>> >      constexpr
>>>>>>> >      _Iterator(_Parent& __parent, _InnerIter<_Const> __inner)
>>>>>>> > -      : _M_parent(std::__addressof(__parent)),
>>>>>>> _M_inner(std::move(__inner))
>>>>>>> > +      : _M_fun(*__parent._M_fun), _M_inner(std::move(__inner))
>>>>>>> >      { }
>>>>>>> >
>>>>>>> >      static auto
>>>>>>> > @@ -5854,14 +6010,14 @@ namespace views::__adaptor
>>>>>>> >      constexpr
>>>>>>> >      _Iterator(_Iterator<!_Const> __i)
>>>>>>> >        requires _Const && convertible_to<_InnerIter<false>,
>>>>>>> _InnerIter<_Const>>
>>>>>>> > -      : _M_parent(__i._M_parent),
>>>>>>> _M_inner(std::move(__i._M_inner))
>>>>>>> > +      : _M_fun(__i._M_fun), _M_inner(std::move(__i._M_inner))
>>>>>>> >      { }
>>>>>>> >
>>>>>>> >      constexpr decltype(auto)
>>>>>>> >      operator*() const
>>>>>>> >      {
>>>>>>> >        return std::apply([&](const auto&... __iters) ->
>>>>>>> decltype(auto) {
>>>>>>> > -        return std::__invoke(*_M_parent->_M_fun, *__iters...);
>>>>>>> > +     return _M_fun._M_call_deref(__iters...);
>>>>>>> >        }, _M_inner._M_current);
>>>>>>> >      }
>>>>>>> >
>>>>>>> > @@ -5913,7 +6069,7 @@ namespace views::__adaptor
>>>>>>> >      operator[](difference_type __n) const requires
>>>>>>> random_access_range<_Base>
>>>>>>> >      {
>>>>>>> >        return std::apply([&](const auto&... __iters) ->
>>>>>>> decltype(auto) {
>>>>>>> > -        return std::__invoke(*_M_parent->_M_fun, __iters[__n]...);
>>>>>>> > +     return _M_fun._M_call_subscript(__n, __iters...);
>>>>>>> >        }, _M_inner._M_current);
>>>>>>> >      }
>>>>>>> >
>>>>>>> > @@ -5950,17 +6106,17 @@ namespace views::__adaptor
>>>>>>> >      friend constexpr _Iterator
>>>>>>> >      operator+(const _Iterator& __i, difference_type __n)
>>>>>>> >        requires random_access_range<_Base>
>>>>>>> > -    { return _Iterator(*__i._M_parent, __i._M_inner + __n); }
>>>>>>> > +    { return _Iterator(__i._M_fun, __i._M_inner + __n); }
>>>>>>> >
>>>>>>> >      friend constexpr _Iterator
>>>>>>> >      operator+(difference_type __n, const _Iterator& __i)
>>>>>>> >        requires random_access_range<_Base>
>>>>>>> > -    { return _Iterator(*__i._M_parent, __i._M_inner + __n); }
>>>>>>> > +    { return _Iterator(__i._M_fun, __i._M_inner + __n); }
>>>>>>> >
>>>>>>> >      friend constexpr _Iterator
>>>>>>> >      operator-(const _Iterator& __i, difference_type __n)
>>>>>>> >        requires random_access_range<_Base>
>>>>>>> > -    { return _Iterator(*__i._M_parent, __i._M_inner - __n); }
>>>>>>> > +    { return _Iterator(__i._M_fun, __i._M_inner - __n); }
>>>>>>> >
>>>>>>> >      friend constexpr difference_type
>>>>>>> >      operator-(const _Iterator& __x, const _Iterator& __y)
>>>>>>> > diff --git
>>>>>>> a/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc
>>>>>>> b/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc
>>>>>>> > index 772e4b3b6a0..1667c6250c5 100644
>>>>>>> > ---
>>>>>>> a/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc
>>>>>>> > +++
>>>>>>> b/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc
>>>>>>> > @@ -113,6 +113,97 @@ test04()
>>>>>>> >    static_assert( requires { x |
>>>>>>> views::pairwise_transform(move_only{}); } );
>>>>>>> >  }
>>>>>>> >
>>>>>>> > +struct X
>>>>>>> > +{
>>>>>>> > +  int i,j;
>>>>>>> > +  constexpr int combine(X o) const
>>>>>>> > +  { return i + o.j; }
>>>>>>> > +};
>>>>>>> > +
>>>>>>> > +template<size_t FuncSize, typename Fn>
>>>>>>> > +constexpr bool
>>>>>>> > +test05(Fn f)
>>>>>>> > +{
>>>>>>> > +  using namespace __gnu_test;
>>>>>>> > +  X x[] = {{1,500},{2,400},{3,300},{4,200},{5,100}};
>>>>>>> > +  test_range<X, random_access_iterator_wrapper> rx(x);
>>>>>>> > +
>>>>>>> > +  auto v = rx | views::pairwise_transform(f);
>>>>>>> > +  VERIFY( ranges::size(v) == 4 );
>>>>>>> > +  VERIFY( ranges::distance(v.begin(), v.end()) == 4 );
>>>>>>> > +  VERIFY( ranges::equal(v, (int[]){401,302,203,104}) );
>>>>>>> > +  VERIFY( ranges::equal(v | views::reverse,
>>>>>>> (int[]){104,203,302,401}) );
>>>>>>> > +  using R = decltype(v);
>>>>>>> > +  using It = ranges::iterator_t<R>;
>>>>>>> > +  static_assert(std::same_as<int, decltype(*ranges::begin(v))>);
>>>>>>> > +  static_assert(std::same_as<int, std::iter_value_t<It>>);
>>>>>>> > +  static_assert(sizeof(It) == 2*sizeof(rx.begin()) + FuncSize);
>>>>>>> > +  static_assert(ranges::view<R>);
>>>>>>> > +  static_assert(ranges::sized_range<R>);
>>>>>>> > +  static_assert(!ranges::common_range<R>);
>>>>>>> > +  static_assert(ranges::random_access_range<R>);
>>>>>>> > +  return true;
>>>>>>> > +}
>>>>>>> > +
>>>>>>> > +constexpr bool
>>>>>>> > +test05a()
>>>>>>> > +{
>>>>>>> > +  auto comb = [](const X& x1, const X& x2) { return x1.i + x2.j;
>>>>>>> };
>>>>>>> > +  return test05<sizeof(void*)>(comb);
>>>>>>> > +}
>>>>>>> > +
>>>>>>> > +constexpr bool
>>>>>>> > +test05b()
>>>>>>> > +{
>>>>>>> > +  auto comb = [](const X& x1, const X& x2) static { return x1.i +
>>>>>>> x2.j; };
>>>>>>> > +  return test05<0>(comb);
>>>>>>> > +}
>>>>>>> > +
>>>>>>> > +constexpr bool
>>>>>>> > +test05c()
>>>>>>> > +{
>>>>>>> > +  int(*comb)(const X&, const X&) = [](const X& x1, const X& x2) {
>>>>>>> return x1.i + x2.j; };
>>>>>>> > +  return test05<sizeof(void(*)())>(comb);
>>>>>>> > +}
>>>>>>> > +
>>>>>>> > +constexpr bool
>>>>>>> > +test05d()
>>>>>>> > +{
>>>>>>> > +  return test05<sizeof(int(X::*)())>(&X::combine);
>>>>>>> > +}
>>>>>>> > +
>>>>>>> > +constexpr bool
>>>>>>> > +test05e()
>>>>>>> > +{
>>>>>>> > +  struct PickStatic
>>>>>>> > +  {
>>>>>>> > +    static constexpr int
>>>>>>> > +    operator()(const X& x1, const X& x2)
>>>>>>> > +    { return x1.i + x2.j; }
>>>>>>> > +
>>>>>>> > +    constexpr int
>>>>>>> > +    operator()(int x, int y) const
>>>>>>> > +    { return x + y; };
>>>>>>> > +  };
>>>>>>> > +  return test05<0>(PickStatic{});
>>>>>>> > +}
>>>>>>> > +
>>>>>>> > +constexpr bool
>>>>>>> > +test05f()
>>>>>>> > +{
>>>>>>> > +  struct PickObject
>>>>>>> > +  {
>>>>>>> > +    constexpr int
>>>>>>> > +    operator()(const X& x1, const X& x2) const
>>>>>>> > +    { return x1.i + x2.j; }
>>>>>>> > +
>>>>>>> > +    static constexpr int
>>>>>>> > +    operator()(int x, int y)
>>>>>>> > +    { return x + y; };
>>>>>>> > +  };
>>>>>>> > +  return test05<sizeof(void*)>(PickObject{});
>>>>>>> > +}
>>>>>>> > +
>>>>>>> >  int
>>>>>>> >  main()
>>>>>>> >  {
>>>>>>> > @@ -120,4 +211,10 @@ main()
>>>>>>> >    static_assert(test02());
>>>>>>> >    static_assert(test03());
>>>>>>> >    test04();
>>>>>>> > +  static_assert(test05a());
>>>>>>> > +  static_assert(test05b());
>>>>>>> > +  static_assert(test05c());
>>>>>>> > +  static_assert(test05d());
>>>>>>> > +  static_assert(test05e());
>>>>>>> > +  static_assert(test05f());
>>>>>>> >  }
>>>>>>> > diff --git
>>>>>>> a/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc
>>>>>>> b/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc
>>>>>>> > index 1788db1ce8d..c6d6b916730 100644
>>>>>>> > --- a/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc
>>>>>>> > +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc
>>>>>>> > @@ -28,12 +28,12 @@ using
>>>>>>> __gnu_test::random_access_iterator_wrapper;
>>>>>>> >  namespace ranges = std::ranges;
>>>>>>> >  namespace views = std::ranges::views;
>>>>>>> >
>>>>>>> > +template<typename Fn>
>>>>>>> >  void
>>>>>>> > -test01()
>>>>>>> > +test01(Fn f)
>>>>>>> >  {
>>>>>>> >    int x[] = {1,2,3,4,5};
>>>>>>> > -  auto is_odd = [] (int i) { return i%2==1; };
>>>>>>> > -  auto v = x | views::transform(is_odd);
>>>>>>> > +  auto v = x | views::transform(f);
>>>>>>> >    VERIFY( ranges::equal(v, (int[]){1,0,1,0,1}) );
>>>>>>> >    using R = decltype(v);
>>>>>>> >    static_assert(std::same_as<bool, decltype(*ranges::begin(v))>);
>>>>>>> > @@ -42,30 +42,124 @@ test01()
>>>>>>> >    static_assert(ranges::random_access_range<R>);
>>>>>>> >  }
>>>>>>> >
>>>>>>> > +void
>>>>>>> > +test01a()
>>>>>>> > +{
>>>>>>> > +  auto is_odd = [] (int i) { return i%2==1; };
>>>>>>> > +  test01(is_odd);
>>>>>>> > +}
>>>>>>> > +
>>>>>>> > +void
>>>>>>> > +test01b()
>>>>>>> > +{
>>>>>>> > +#if __cpp_static_call_operator >= 202207L
>>>>>>> > +  auto is_odd = [] (int i) static { return i%2==1; };
>>>>>>> > +  test01(is_odd);
>>>>>>> > +#endif
>>>>>>> > +}
>>>>>>> > +
>>>>>>> > +void
>>>>>>> > +test01c()
>>>>>>> > +{
>>>>>>> > +  bool(*is_odd)(int) = [] (int i) { return i%2==1; };
>>>>>>> > +  test01(is_odd);
>>>>>>> > +}
>>>>>>> > +
>>>>>>> >  struct X
>>>>>>> >  {
>>>>>>> >    int i,j;
>>>>>>> > +  int& first() { return i; }
>>>>>>> >  };
>>>>>>> >
>>>>>>> > +template<size_t FuncSize, typename Fn>
>>>>>>> >  void
>>>>>>> > -test02()
>>>>>>> > +test02(Fn f)
>>>>>>> >  {
>>>>>>> >    X x[] = {{1,2},{3,4},{5,6},{7,8},{9,10}};
>>>>>>> >    test_range<X, random_access_iterator_wrapper> rx(x);
>>>>>>> > -  auto v = rx | views::transform(&X::i);
>>>>>>> > +  auto v = rx | views::transform(f);
>>>>>>> >    VERIFY( ranges::size(v) == 5 );
>>>>>>> >    VERIFY( ranges::distance(v.begin(), v.end()) == 5 );
>>>>>>> >    VERIFY( ranges::equal(v, (int[]){1,3,5,7,9}) );
>>>>>>> >    VERIFY( ranges::equal(v | views::reverse, (int[]){9,7,5,3,1}) );
>>>>>>> >    using R = decltype(v);
>>>>>>> > +  using It = ranges::iterator_t<R>;
>>>>>>> >    static_assert(std::same_as<int&, decltype(*ranges::begin(v))>);
>>>>>>> > -  static_assert(std::same_as<int,
>>>>>>> std::iter_value_t<ranges::iterator_t<R>>>);
>>>>>>> > +  static_assert(std::same_as<int, std::iter_value_t<It>>);
>>>>>>> > +  static_assert(sizeof(It) == sizeof(rx.begin()) + FuncSize);
>>>>>>> >    static_assert(ranges::view<R>);
>>>>>>> >    static_assert(ranges::sized_range<R>);
>>>>>>> >    static_assert(!ranges::common_range<R>);
>>>>>>> >    static_assert(ranges::random_access_range<R>);
>>>>>>> >  }
>>>>>>> >
>>>>>>> > +void
>>>>>>> > +test02a()
>>>>>>> > +{ test02<sizeof(int X::*)>(&X::i); }
>>>>>>> > +
>>>>>>> > +void
>>>>>>> > +test02b()
>>>>>>> > +{ test02<sizeof(int(X::*)())>(&X::first); }
>>>>>>> > +
>>>>>>> > +void
>>>>>>> > +test02c()
>>>>>>> > +{
>>>>>>> > +  auto first = [](X& x) -> int& { return x.i; };
>>>>>>> > +  test02<sizeof(void*)>(first);
>>>>>>> > +}
>>>>>>> > +
>>>>>>> > +void
>>>>>>> > +test02d()
>>>>>>> > +{
>>>>>>> > +#if __cpp_static_call_operator >= 202207L
>>>>>>> > +  auto first = [](X& x) static -> int& { return x.i; };
>>>>>>> > +  test02<0>(first);
>>>>>>> > +#endif
>>>>>>> > +}
>>>>>>> > +
>>>>>>> > +void
>>>>>>> > +test02e()
>>>>>>> > +{
>>>>>>> > +  int&(*fptr)(X&) = [](X& x) -> int& { return x.i; };
>>>>>>> > +  test02<sizeof(void(*)())>(fptr);
>>>>>>> > +}
>>>>>>> > +
>>>>>>> > +void
>>>>>>> > +test02f()
>>>>>>> > +{
>>>>>>> > +#if __cpp_static_call_operator >= 202207L
>>>>>>> > +  struct PickStatic
>>>>>>> > +  {
>>>>>>> > +    static constexpr int&
>>>>>>> > +    operator()(X& x)
>>>>>>> > +    { return x.i; }
>>>>>>> > +
>>>>>>> > +    constexpr int
>>>>>>> > +    operator()(char*) const
>>>>>>> > +    { return 0; };
>>>>>>> > +  };
>>>>>>> > +  test02<0>(PickStatic{});
>>>>>>> > +#endif
>>>>>>> > +}
>>>>>>> > +
>>>>>>> > +void
>>>>>>> > +test02g()
>>>>>>> > +{
>>>>>>> > +#if __cpp_static_call_operator >= 202207L
>>>>>>> > +  struct PickObject
>>>>>>> > +  {
>>>>>>> > +    constexpr int&
>>>>>>> > +    operator()(X& x) const
>>>>>>> > +    { return x.i; }
>>>>>>> > +
>>>>>>> > +    static constexpr int
>>>>>>> > +    operator()(char*)
>>>>>>> > +    { return 0; };
>>>>>>> > +  };
>>>>>>> > +  test02<sizeof(void*)>(PickObject{});
>>>>>>> > +#endif
>>>>>>> > +}
>>>>>>> > +
>>>>>>> >  void
>>>>>>> >  test03()
>>>>>>> >  {
>>>>>>> > @@ -230,8 +324,16 @@ test11()
>>>>>>> >  int
>>>>>>> >  main()
>>>>>>> >  {
>>>>>>> > -  test01();
>>>>>>> > -  test02();
>>>>>>> > +  test01a();
>>>>>>> > +  test01b();
>>>>>>> > +  test01c();
>>>>>>> > +  test02a();
>>>>>>> > +  test02b();
>>>>>>> > +  test02c();
>>>>>>> > +  test02d();
>>>>>>> > +  test02e();
>>>>>>> > +  test02f();
>>>>>>> > +  test02g();
>>>>>>> >    test03();
>>>>>>> >    test04();
>>>>>>> >    test05();
>>>>>>> > diff --git a/libstdc++-v3/testsuite/std/ranges/zip_transform/1.cc
>>>>>>> b/libstdc++-v3/testsuite/std/ranges/zip_transform/1.cc
>>>>>>> > index 9a0ad3814e6..d4bd7db26cb 100644
>>>>>>> > --- a/libstdc++-v3/testsuite/std/ranges/zip_transform/1.cc
>>>>>>> > +++ b/libstdc++-v3/testsuite/std/ranges/zip_transform/1.cc
>>>>>>> > @@ -132,6 +132,97 @@ test04()
>>>>>>> >    static_assert( requires { views::zip_transform(move_only{}, x,
>>>>>>> x); } );
>>>>>>> >  }
>>>>>>> >
>>>>>>> > +struct X
>>>>>>> > +{
>>>>>>> > +  int i;
>>>>>>> > +  constexpr int add(int b) const
>>>>>>> > +  { return i+b; }
>>>>>>> > +};
>>>>>>> > +
>>>>>>> > +template<size_t ExtraSize, typename Fn>
>>>>>>> > +constexpr bool
>>>>>>> > +test05(Fn f)
>>>>>>> > +{
>>>>>>> > +  using namespace __gnu_test;
>>>>>>> > +  X x[] = {{1},{2},{3},{4},{5}};
>>>>>>> > +  int y[] = {500,400,300,200,100};
>>>>>>> > +  test_range<X, random_access_iterator_wrapper> rx(x);
>>>>>>> > +  test_range<int, random_access_iterator_wrapper> ry(y);
>>>>>>> > +
>>>>>>> > +  auto v = views::zip_transform(f, rx, ry);
>>>>>>> > +  VERIFY( ranges::size(v) == 5 );
>>>>>>> > +  VERIFY( ranges::distance(v.begin(), v.end()) == 5 );
>>>>>>> > +  VERIFY( ranges::equal(v, (int[]){501,402,303,204,105}) );
>>>>>>> > +  VERIFY( ranges::equal(v | views::reverse,
>>>>>>> (int[]){105,204,303,402,501}) );
>>>>>>> > +  using R = decltype(v);
>>>>>>> > +  using It = ranges::iterator_t<R>;
>>>>>>> > +  static_assert(std::same_as<int, decltype(*ranges::begin(v))>);
>>>>>>> > +  static_assert(std::same_as<int, std::iter_value_t<It>>);
>>>>>>> > +  static_assert(sizeof(It) == sizeof(rx.begin()) +
>>>>>>> sizeof(ry.begin()) + ExtraSize);
>>>>>>> > +  static_assert(ranges::view<R>);
>>>>>>> > +  static_assert(ranges::sized_range<R>);
>>>>>>> > +  static_assert(ranges::common_range<R>);
>>>>>>> > +  static_assert(ranges::random_access_range<R>);
>>>>>>> > +  return true;
>>>>>>> > +}
>>>>>>> > +
>>>>>>> > +constexpr bool
>>>>>>> > +test05a()
>>>>>>> > +{
>>>>>>> > +  auto add = [](const X& x, int v) { return x.i + v; };
>>>>>>> > +  return test05<sizeof(void*)>(add);
>>>>>>> > +}
>>>>>>> > +
>>>>>>> > +constexpr bool
>>>>>>> > +test05b()
>>>>>>> > +{
>>>>>>> > +  auto add = [](const X& x, int v) static { return x.i + v; };
>>>>>>> > +  return test05<0>(add);
>>>>>>> > +}
>>>>>>> > +
>>>>>>> > +constexpr bool
>>>>>>> > +test05c()
>>>>>>> > +{
>>>>>>> > +  int(*ptr)(const X&, int) = [](const X& x, int v) { return x.i +
>>>>>>> v; };
>>>>>>> > +  return test05<sizeof(void(*)())>(ptr);
>>>>>>> > +}
>>>>>>> > +
>>>>>>> > +constexpr bool
>>>>>>> > +test05d()
>>>>>>> > +{ return test05<sizeof(int(X::*)())>(&X::add); }
>>>>>>> > +
>>>>>>> > +constexpr bool
>>>>>>> > +test05e()
>>>>>>> > +{
>>>>>>> > +  struct PickStatic
>>>>>>> > +  {
>>>>>>> > +    static constexpr int
>>>>>>> > +    operator()(const X& x1, int v)
>>>>>>> > +    { return x1.i + v; }
>>>>>>> > +
>>>>>>> > +    constexpr int
>>>>>>> > +    operator()(int x, int y) const
>>>>>>> > +    { return x + y; };
>>>>>>> > +  };
>>>>>>> > +  return test05<0>(PickStatic{});
>>>>>>> > +}
>>>>>>> > +
>>>>>>> > +constexpr bool
>>>>>>> > +test05f()
>>>>>>> > +{
>>>>>>> > +  struct PickObject
>>>>>>> > +  {
>>>>>>> > +    constexpr int
>>>>>>> > +    operator()(const X& x1, int v) const
>>>>>>> > +    { return x1.i + v; }
>>>>>>> > +
>>>>>>> > +    static constexpr int
>>>>>>> > +    operator()(int x, int y)
>>>>>>> > +    { return x + y; };
>>>>>>> > +  };
>>>>>>> > +  return test05<sizeof(void*)>(PickObject{});
>>>>>>> > +}
>>>>>>> > +
>>>>>>> >  int
>>>>>>> >  main()
>>>>>>> >  {
>>>>>>> > @@ -139,4 +230,14 @@ main()
>>>>>>> >    static_assert(test02());
>>>>>>> >    static_assert(test03());
>>>>>>> >    test04();
>>>>>>> > +  static_assert(test01());
>>>>>>> > +  static_assert(test02());
>>>>>>> > +  static_assert(test03());
>>>>>>> > +  test04();
>>>>>>> > +  static_assert(test05a());
>>>>>>> > +  static_assert(test05b());
>>>>>>> > +  static_assert(test05c());
>>>>>>> > +  static_assert(test05d());
>>>>>>> > +  static_assert(test05e());
>>>>>>> > +  static_assert(test05f());
>>>>>>> >  }
>>>>>>> > --
>>>>>>> > 2.51.0
>>>>>>> >
>>>>>>> >
>>>>>>
>>>>>>

Reply via email to