[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