[Bug libstdc++/99433] [11 Regression] custom friend pipe-operator| conflicts with range adaptor?

gcc-bugs at marehr dot dialup.fu-berlin.de gcc-bugzilla@gcc.gnu.org
Mon Mar 8 21:23:54 GMT 2021


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


More information about the Gcc-bugs mailing list