Steven Schveighoffer wrote:
"Andrei Alexandrescu" wrote
I'm working on the new range stuff and the range-based algorithm. In all
likelihood, you all might be pleased with the results.
I wanted to gauge opinions on a couple of issues. One is, should the
empty() member function for ranges be const? On the face of it it should,
but I don't want that to be a hindrance. I presume non-const empty might
be necessary sometimes, e.g. figuring out if a stream is empty effectively
means fetching an element off it.
Ranges are structs. It should not matter if you want to make some const and
some non-const. Basically, it depends on the range implementation. If you
can make it const, make it const, if not, don't make it const. It shouldn't
break any APIs.
The problem is "higher-order" ranges - ranges that take other ranges as
argument. For example, consider Retro, a range that iterates another
range backwards.
struct Retro(Range)
{
Range _input;
...
bool empty() { return _input.empty; }
}
If Retro.empty is const and Range.empty is not, that won't compile. If
Retro.empty is non-const and Range.empty is const, it will compile, but
passing a const Retro won't work as well as passing a const Range.
For example, an array range might have empty be const, but a stream range
might not. What matters is what functions you can use those ranges in, but
those are generally templated functions, so the compiler will tell you
whether it can be used or not when it tries to compile it.
Personally, I see no benefit to having empty() be const. What benefits do
you gain by specifically making empty const and the other functions not
const? Presumably, the underlying container must be not const in order for
head, next, etc. to work properly, so there is no requirement there.
If you have a constant range with random access, empty, length, and
opIndex should be enough for you to look at anything you want without
altering the range itself.
Andrei