2

Consider the following code

#include <ranges>
#include <iostream>
int main() {
  auto int_view = std::views::iota(0, 20) | std::views::take(15);
  std::cout << int_view.size() << std::endl;
  return 0;
}

This compiles fine and prints 15 as the size of int_view. However if we make the iota unbounded like iota(0) instead of iota(0,20), then that code won't compile because std::ranges::take_view<_Vp>::size() requires a sized_range, which the unbounded iota is clearly not. My question is why does it require a sized range? once we take a number of elements the corresponding view should be able to know it's size in constant time.

HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207
Reimundo Heluani
  • 918
  • 9
  • 18

1 Answers1

4

views::take only guarantees an upper bound on the size of the range, not its exact size which is what .size() must return.

C++ ranges/views are either bounded (have .size() and satisfy std::ranges::sized_range) or unbounded, there is no finer distinction for infinite ranges or minimum-/maximum-guaranteed lengths.

iota(0) returns an unbounded range, views::take therefore has no idea how many elements there are, could be zero or could be infinite for all it knows, and so the take must be of unknown size - unbounded.

Quimby
  • 17,735
  • 4
  • 35
  • 55
  • 1
    Note that just because a range is non-sized does not mean that it is "unbounded". An unbounded range is one where the iterators will never be equal to any sentinel value. An unsized range may be one where there is a size, but computing it is a linear-time operation. – Nicol Bolas Sep 19 '22 at 20:02
  • This comment, specially the last statement, actually clarifies the situation more than the answer: I can see how take can know the size as there must be one, but can not be known in constant time – Reimundo Heluani Sep 20 '22 at 00:41