5

If I create a view, then it's a range. That seems reasonable.

However, if it's const, then it becomes a non-range:

#include <ranges>

int main()
{
    int values[] = { 1, 2, 3 };

    auto odd_values = values | std::views::filter([](int i){ return i % 2; });
    static_assert(std::ranges::range<decltype(odd_values)>);

    auto const odd_ref = odd_values;    
    static_assert(!std::ranges::range<decltype(odd_ref)>); // WHY NOT?
}

This is surprising - I don't see any reason I shouldn't be able to read the contents, just as I could from, say a const std::vector.

In case it's an implementation bug, I experienced this with GCC 11, using -std=c++20; library is libstdc++-11.


If I add a call to std::ranges::begin() I get plenty of diagnostics, showing it not finding a member function nor anything via ADL, then running up against the backstop deleted function that's there to prevent std::begin matching.

From the error messages, it seems that we're lacking const versions of begin() and end() member functions from the view class. Is that expected, or have they just been missed out?

That led me to a simpler failing example:

#include <ranges>

int main()
{
    int values[] = { 1, 2, 3 };

    auto const odd_values = values | std::views::filter([](int i){ return i % 2; });

    odd_values.begin();  // ERROR HERE
}
view.cpp: In function ‘int main()’:
view.cpp:9:21: error: passing ‘const std::ranges::filter_view<std::ranges::ref_view<int [3]>, main()::<lambda(int)> >’ as ‘this’ argument discards qualifiers [-fpermissive]
    9 |     odd_values.begin();  // ERROR HERE
      |     ~~~~~~~~~~~~~~~~^~
In file included from view.cpp:1:
/usr/include/c++/11/ranges:1452:7: note:   in call to ‘constexpr std::ranges::filter_view<_Vp, _Pred>::_Iterator std::ranges::filter_view<_Vp, _Pred>::begin() [with _Vp = std::ranges::ref_view<int [3]>; _Pred = main()::<lambda(int)>]’
 1452 |       begin()
      |       ^~~~~

So why doesn't the view have const versions of begin() and end()?

Toby Speight
  • 27,591
  • 48
  • 66
  • 103
  • FWIW, compiles clean in vs2022 with /stdc++latest – pm100 Feb 18 '22 at 22:03
  • @pm100, does latest start implementing some changes from c++23 drafts which change the behaviour? Or does it also compile in C++20? – ChrisMM Feb 18 '22 at 22:16
  • doesnt even recognize `std::views` in c++20 – pm100 Feb 18 '22 at 22:19
  • @pm100 Yes. The question is: _why_ does it compile clean? OP is asserting that `odd_ref` is _NOT_ a range, and the question is why not? – Barry Feb 18 '22 at 23:07
  • @Barry - I have no idea - hence the 'FWIW in my comment. I dont even know what these things (ranges, views etc) do although I will go look now – pm100 Feb 18 '22 at 23:44
  • @pm100 That's what I'm trying to explain: the fact that it compiles clean _is the question_: why does it compile clean, when OP expected it not to? – Barry Feb 18 '22 at 23:55
  • 1
    Thanks @康桓瑋 for finding the duplicate - I did look hard, I promise. – Toby Speight Feb 19 '22 at 08:04
  • @pm100 - just to clarify (I didn't read carefully enough yesterday) - are you saying that `std::ranges::begin(odd_ref)` compiles cleanly on your platform? Or that `std::ranges::range`is false, as shown here? If the former, it seems that that the linked question explains one approach to achieving the complexity requirements in a thread-safe way, and it might be worth you adding a comment over on that question. – Toby Speight Feb 19 '22 at 08:08
  • 2
    @TobySpeight Note that *not* all range adaptors have this time complexity requirement, most range adaptors are indeed const-iterable if specific constraints are satisfied. I've added a new answer below the origin. – 康桓瑋 Feb 19 '22 at 10:24

0 Answers0