https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99433
gcc-bugs at marehr dot dialup.fu-berlin.de changed: What |Removed |Added ---------------------------------------------------------------------------- Summary|custom friend |[11 Regression] custom |pipe-operator| conflicts |friend pipe-operator| |with range adaptor? |conflicts with range | |adaptor? Component|c++ |libstdc++ --- Comment #1 from gcc-bugs at marehr dot dialup.fu-berlin.de --- Hello gcc-team, I got the code more recuced to: ```c++ namespace std { template <typename _Tp, typename _Up = _Tp &&> _Up __declval(int); template <typename _Tp> auto declval() noexcept -> decltype(__declval<_Tp>(0)); } // namespace std namespace std::ranges { struct view_base {}; template <typename _Derived> class view_interface : public view_base {}; } // namespace std::ranges namespace std::ranges::views::__adaptor { template <typename _Callable> struct _RangeAdaptorClosure; template <typename _Callable> struct _RangeAdaptor { _Callable _M_callable; constexpr _RangeAdaptor(const _Callable & __callable) : _M_callable{__callable} {} template <typename... _Args> constexpr auto operator()(_Args &&...__args) const { auto __closure = [... __args(__args)]<typename _Range>(_Range &&__r) { return _Callable{}(__r, __args...); }; using _ClosureType = decltype(__closure); return _RangeAdaptorClosure{__closure}; } }; template <typename _Callable> struct _RangeAdaptorClosure : public _RangeAdaptor<_Callable> { template <typename _Range> requires requires {declval<_Callable>()(declval<_Range>());} friend constexpr auto operator|(_Range &&__r, const _RangeAdaptorClosure &__o); }; template <typename _Callable> _RangeAdaptorClosure(_Callable) -> _RangeAdaptorClosure<_Callable>; } // namespace std::ranges::views::__adaptor namespace std::ranges { template <typename _Vp, typename _Fp> class transform_view : public view_interface<transform_view<_Vp, _Fp>> {}; } // namespace std::ranges namespace std::ranges::views { inline constexpr __adaptor::_RangeAdaptor transform = [](auto &&__r, auto &&__f) { return transform_view{__r, __f}; }; } // namespace std::ranges::views namespace std { namespace views = ranges::views; template <typename _Tp> class vector {}; } // namespace std template <typename underlying_adaptor_t> struct deep { underlying_adaptor_t adaptor; template <typename range_t> friend auto operator|(range_t &range, deep const &me) { return 0; } }; template <typename underlying_adaptor_t> deep(underlying_adaptor_t && adaptor) -> deep<underlying_adaptor_t>; inline auto const complement = deep{std::views::transform([]() {})}; std::vector<std::vector<char>> foo; auto v = foo | complement; ``` See https://godbolt.org/z/51d9da AFAIS the problem is that ```c++ template <typename _Range> requires requires {declval<_Callable>()(declval<_Range>());} std::ranges::views::__adaptor::_RangeAdaptorClosure::operator|(_Range &&__r, const _RangeAdaptorClosure &__o) ``` does not constraint the second argument to be `_RangeAdaptorClosure &__o`. If I see this correctly, this is the same issue as in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97704 (which was marked invalid). Just that this time your std-lib implementation is at fault. I still find it insane that a non-template argument that does not fit is somehow considered in a requires expression, since this effectively forbids to use constraints on non template or partial template functions, but it is as it is, and it would be cool if the std-lib implementation plays by the same rules. (Why isn't a constraint with the type added implicitly to the requires clause in these cases? That seems to be a workaround anyway...)