1

When using boost::any_range, what's the correct way of specifying that the underlying container (if any) shouldn't be modified?

E.g., with the alias

template<typename T>
using Range = boost::any_range<T, boost::forward_traversal_tag>;

to declare a range that isn't capable of modifying the contents of the underlying container or "data source", should it be declared as

const Range<T> myRange;

or as

Range<const T> myRange;

?

I suspect the first version is the correct one. But is it guaranteed to keep the constness of the container, if, for example, I apply any of the boost::adaptors?


Edit

From the documentation, apparently the range_iterator metafunction "deduces" the constness of the underlying container by declaring the range with const T instead of T. That is, range_iterator::<const T>::type is const_iterator (if the underlying container has such member type), instead of iterator, so the container can't be modified through this iterator.

Does that mean that Range<const T> also uses const_iterators to traverse the range?

Anakhand
  • 2,838
  • 1
  • 22
  • 50
  • 1
    `Range` and `const Range` are two *very* different things. The first (`Range`) is a `Range` of constant `T`. The second (`const Range`) is a constant `Range` of non-constant `T`. It's the same difference between e.g. `std::vector` and `const std::vector`. – Some programmer dude Mar 22 '19 at 08:38
  • @Someprogrammerdude Except that `const Range` might still be able to modify the underlying container, while `Range` may deduce the `const`ness (that is, use `const_iterator`s instead of `iterator`s) from the `range_iterator` metafunction. So, what exactly is a constant `Range`? One that uses `const_iterators` or one whose "wrapper" members don't change (but the underlying container might)? – Anakhand Mar 22 '19 at 08:54
  • `void f(const Range)` doesn't do what you think. See [Top-level const doesn't influence a function signature](https://stackoverflow.com/q/17208570/1639256). – Oktalist Mar 22 '19 at 15:24
  • @Oktalist Yes, but that's beside the point. I'm asking whether a `const Range` can modify the underlying container; I'm not asking how to overload the function based on the `Range` *object*'s `const`ness---which in principle could be independent of the underlying container's `const`ness. The function was just an example. I'll clarify. – Anakhand Mar 22 '19 at 15:33
  • 1
    @Someprogrammerdude: You can’t actually make `std::vector`, though. – Davis Herring Mar 23 '19 at 01:52

1 Answers1

0

Apparently the correct way to ensure that the values aren't modified is neither of those I mentioned.

From Boost.Range's documentation, we can see that any_range takes the following template parameters:

template<
    class Value
  , class Traversal
  , class Reference
  , class Difference
  , class Buffer = any_iterator_default_buffer
>
class any_range;

I strongly suspect the way to declare a "const range" is to specify const T as the Reference type template parameter, although, surprisingly, I still haven't been able to find any explicit indication in the documentation that this is so.

So a const range could be declared as:

template<class C>
using ConstRange = boost::any_range<C, boost::forward_traversal_tag, const C, std::ptrdiff_t>
Anakhand
  • 2,838
  • 1
  • 22
  • 50