Why is `iota(0) | common` not a `random_access_range`?

1 week ago 14
ARTICLE AD BOX

We can use iota as a random_access_range:

static_assert(random_access_range<decltype(iota(0))>); // ok cout << (iota(0))[1]; // 1

However, if we pass it via the range adapter common to get a common_range, the result is no longer a random_access_range:

static_assert(random_access_range<decltype(iota(0) | common)>); // fails

This becomes relevant in actual code, if we get an iota through a take and wish to calculate distance:

auto iota_2 = iota(0) | take(2); // cannot take distance, end is still a sentinel static_assert(!common_range<decltype(iota(0) | take(2))>); // auto diff_iota_2 = std::distance(iota_2.begin(), iota_2.end()); // compilation error

So, we take the view through common adapter:

auto iota_2_common = iota(0) | take(2) | common; // now we can calculate distance if needed auto diff_iota_2 = distance(iota_2_common.begin(), iota_2_common.end());

But, then we lost random access:

cout << iota_2_common[1]; // compilation error, iota_2_common is not random access

Yes, we can use for the above iota(0, 2) which by itself is both random_access_range and common_range, thus supporting both required operations: distance and access by index. However, let's assume we started with an unbounded random access view, like iota, and we want to use take and common on it, then be able to still access it by index and calculate distance. Why is it not supported?


Code: https://gcc.godbolt.org/z/4c6Tabzx6

Read Entire Article