Search code examples
c++range-v3

Why is a simple iterator not readable?


This code does not compile with range-v3 0.10.0 (or with master). It does compile with range-v3 0.9.1.

#include "range/v3/all.hpp"

struct double_it {
  using value_type = double;
  double x;
  double& operator*() { return x; }
  const double& operator*() const { return x; }
};
static_assert(ranges::readable<double_it>);

Which version is right ? In master, a type I is readable only if same_as<iter_reference_t<I const>, iter_reference_t<I>>. I don't understand why the return type of operator* should be the same as the one of operator* const.

Note: issue submitted on github here.


Solution

  • Take a look at P1878, which has all the rationale for this late design change. Iterators represent indirections. In C++, const-ness is shallow, meaning it doesn't follow indirections. Whether you dereference an int* or an int*const, the result you get back is the same: int&. The top-level const doesn't -- and shouldn't -- matter. Iterators do as the pointers do. They must, because a pointer is a valid model of the iterator concept.

    To make this distinction more explicit, in C++20, the readable concept is called indirectly_readable.

    TL;DR: Don't make the reference type of your iterator depend on the const-ness of the iterator itself.