3

The following code compiles:

#if 0 /*
g++ -std=c++23 $0 -o exe \
  -Wall -Werror -Wextra -Wsign-conversion -pedantic-errors \
  && ./exe $@
RET=$?
rm -f exe
exit $RET
*/
#endif

#include <expected>
#include <ranges>
#include <vector>

int main() {
  auto v = std::vector{std::expected<int, int>(0)};
  auto r1 = std::views::all(std::vector{0});
  // auto r2 = std::views::all(v);
}

But if I uncomment the definition of r2, I get the following error:

In file included from ./expected-in-range.cpp:11:
/usr/include/c++/15.1.1/expected: In substitution of ‘template<class _Up>  requires !(__is_expected<_Up>) && requires(const _Tp& __t, const _Up& __u) {{__t == __u} -> decltype(auto) [requires std::convertible_to<<placeholder>, bool>];} constexpr bool std::operator==(const expected<int, int>&, const _Up&) [with _Up = __gnu_cxx::__normal_iterator<std::expected<int, int>*, std::vector<std::expected<int, int>, std::allocator<std::expected<int, int> > > >]’:
/usr/include/c++/15.1.1/expected:1175:12:   required by substitution of ‘template<class _Up>  requires !(__is_expected<_Up>) && requires(const _Tp& __t, const _Up& __u) {{__t == __u} -> decltype(auto) [requires std::convertible_to<<placeholder>, bool>];} constexpr bool std::operator==(const expected<int, int>&, const _Up&) [with _Up = __gnu_cxx::__normal_iterator<std::expected<int, int>*, std::vector<std::expected<int, int>, std::allocator<std::expected<int, int> > > >]’
 1175 |             { __t == __u } -> convertible_to<bool>;
      |               ~~~~^~~~~~
/usr/include/c++/15.1.1/concepts:306:10:   required by substitution of ‘template<class _Tp>  requires (__maybe_borrowed_range<_Tp>) && ((is_bounded_array_v<typename std::remove_reference<_Tp>::type>) || (__member_end<_Tp>) || (__adl_end<_Tp>)) constexpr auto std::ranges::__access::_End::operator()(_Tp&&) const [with _Tp = std::vector<std::expected<int, int>, std::allocator<std::expected<int, int> > >&]’
  306 |           { __t == __u } -> __boolean_testable;
      |             ~~~~^~~~~~
/usr/include/c++/15.1.1/bits/ranges_base.h:517:13:   required by substitution of ‘template<class _Range>  requires (viewable_range<_Range>) && ((view<typename std::decay<_Tp>::type>) || (__can_ref_view<_Range>) || (__can_owning_view<_Range>)) constexpr auto std::ranges::views::_All::operator()(_Range&&) const [with _Range = std::vector<std::expected<int, int>, std::allocator<std::expected<int, int> > >&]’
  517 |         ranges::end(__t);
      |         ~~~~~~~~~~~^~~~~
./expected-in-range.cpp:18:28:   required from here
   18 |   auto r2 = std::views::all(v);
      |             ~~~~~~~~~~~~~~~^~~
/usr/include/c++/15.1.1/expected:1178:2:   required by the constraints of ‘template<class _Tp, class _Er> template<class _Up>  requires !(__is_expected<_Up>) && requires(const _Tp& __t, const _Up& __u) {{__t == __u} -> decltype(auto) [requires std::convertible_to<<placeholder>, bool>];} constexpr bool std::operator==(const expected<_Tp, _Er>&, const _Up&)’
/usr/include/c++/15.1.1/expected:1174:7:   in requirements with ‘const _Tp& __t’, ‘const _Up& __u’ [with _Tp = int; _Up = __gnu_cxx::__normal_iterator<std::expected<int, int>*, std::vector<std::expected<int, int>, std::allocator<std::expected<int, int> > > >]
/usr/include/c++/15.1.1/expected:1174:14: error: satisfaction of atomic constraint ‘requires(const _Tp& __t, const _Up& __u) {{__t == __u} -> decltype(auto) [requires std::convertible_to<<placeholder>, bool>];} [with _Tp = _Tp; _Up = _Up]’ depends on itself
 1174 |           && requires (const _Tp& __t, const _Up& __u) {
      |              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 1175 |             { __t == __u } -> convertible_to<bool>;
      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 1176 |           }
      |           ~   

How am I meant to understand that error? What does it mean? How can I do what I'm trying to do?

The above is an SSCCE - the full thing I'm trying to do is have a function that accepts some iterable of ints, a second function that returns an expected<int, Something>, and pass the output of a bunch of invocations of the second function to the first by doing

f(
  all(std::vector{g(), g(), g()})
  | filter([](auto e){ return e.has_value(); })
  | transform([](auto e){ return e.value(); })
);

So if there's a less foolish way of doing that, I'd also accept that as an answer.

11
  • 1
    For what it's worth, when I tried your test code on Godbolt, it didn't compile with gcc 15.1 (as expected) but did compile with clang 20.1.0: godbolt.org/z/49szEP54q Commented Jun 20 at 17:34
  • 1
    Could be a bug in gcc as well. Judging from en.cppreference.com/w/cpp/ranges/all_view.html, it doesn't look like you're doing something obviously wrong. Commented Jun 20 at 17:41
  • 1
    it looks like when constructing a range from the vector, it's trying to find operator==(expected<int,int>, vector::iterator) for some reason, but I can't fathom why. Commented Jun 20 at 17:42
  • 3
    After studying the details deeper, it seems to be have something to do with checking if this is a "borrowed" range, and dangling pointer checks. But regardless of the reason, it shouldn't be comparing elements to iterators, so you've found a bug in this std::range implementation code. Commented Jun 20 at 17:47
  • 2
    No, you definitely found a bug. It should definitely not be comparing an element to an iterator. I'm just trying to work out how to bypass the bug Commented Jun 20 at 17:52

1 Answer 1

9

This is a GCC Bug 119714 which has been fixed in trunk.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.