5

I can't call ranges::begin on a const filter_view

https://en.cppreference.com/w/cpp/ranges/filter_view the begin and end doesn't seem to be const. why is that?

int main(){
    std::vector v{1,2,3};
    // removing const will make it compile
    const auto r = v | ranges::views::filter ([](auto&&){return true;}); 
    ranges::begin(r);
}

https://godbolt.org/z/4feaYc

Hui
  • 571
  • 1
  • 3
  • 9
  • can't find a dupe right now, but this has been discussed, and it's because the view might have internal state, which can be modified by getting an iterator, etc. basically, you want this thread: https://github.com/ericniebler/range-v3/issues/385 – underscore_d Feb 25 '21 at 09:48

1 Answers1

3

All the views in std::range library are lazy by design. What it means in practice? It means that under the hood they usually do much more on begin, end and iterator operations than regular containers. Usually to be able to maintain this laziness some internal state is required. For example filtred view can store iterator to the last matching element or something along these lines. In this case begin() changes this internal field. Even the cppreference says this about begin:

Returns the iterator initialized with {*this, ranges::find_if(base_, std::ref(*pred_))}. In order to provide the amortized constant time complexity required by the range concept, this function caches the result within the filter_view object for use on subsequent calls.

So it makes perfect sense - since there CAN (and most probably is) an internal state which begin() and/or end() can modify they cannot be made const.

bartop
  • 9,971
  • 1
  • 23
  • 54
  • why does boost filtered range work with const?https://godbolt.org/z/Ge1cb8 – Hui Feb 25 '21 at 13:11
  • 1
    @Hui Presumably because it's not lazy by design... or maybe it is but they use `mutable` members, although I have no idea whether that's a design that can work. – underscore_d Feb 25 '21 at 14:01