I am having trouble using view_facade (from range-v3) to create a view that provides both const and non-const access. As an example, I tried modifying the view_facade test (in test/view_facade.cpp) to allow non-const access (by default it only allows const access):
struct MyRange
: ranges::range_facade<MyRange>
{
private:
friend struct ranges::range_access;
std::vector<int> ints_;
template <bool isConst>
struct cursor
{
private:
using It = typename std::conditional<isConst, std::vector<int>::const_iterator, std::vector<int>::iterator>::type;
using RefType = typename std::conditional<isConst, int const&, int&>::type;
It iter;
public:
cursor() = default;
cursor(It it)
: iter(it)
{}
RefType current() const
{
return *iter;
}
//...
};
/* // Uncommenting these overloads will cause an error, below.
cursor<true> begin_cursor() const
{
return {ints_.begin()};
}
cursor<true> end_cursor() const
{
return {ints_.end()};
}
*/
cursor<false> begin_cursor()
{
return {ints_.begin()};
}
cursor<false> end_cursor()
{
return {ints_.end()};
}
public:
MyRange()
: ints_{1, 2, 3, 4, 5, 6, 7}
{}
};
int main() {
MyRange nc;
int& nci = *nc.begin(); // error here when const overloads present.
}
Full code here.
This works fine with the const overloads of begin_cursor and end_cursor commented out. However, if I add those overloads back in, the following error is generated on the indicated line (GCC 5.1):
error: binding 'const int' to reference of type 'int&' discards qualifiers
It seems to be selecting the const version, giving me a const iterator. What I want is: const iterators for const objects, and non-const iterators for non-const objects. How can I achieve that?
Range v3 is a generic library that augments the existing standard library with facilities for working with ranges. A range can be loosely thought of a pair of iterators, although they need not be implemented that way.
The library used in the code examples is not really the C++20 ranges, it's the ranges-v3 open-source library from Eric Niebler, which is the basis of the proposal to add ranges to the C++. It's a header-only library compatible with C++11/14/17.
A const iterator points to an element of constant type which means the element which is being pointed to by a const_iterator can't be modified. Though we can still update the iterator (i.e., the iterator can be incremented or decremented but the element it points to can not be changed).
view_facade
is for building views. Views refer to data they don't own. They are like pointers in that logically they are indirections. And like pointers, top-level const
should have no effect on the const
-ness of the data referenced. That is whether you dereference an int*
or an int*const
, the result is the same: int&
.
Your view is not a view. It owns its data. (See the vector<int> ints_
data member.) Trying to use view_facade
to turn this data structure into a view is bound to lead to frustration. This is very much by design. Views are distinct from containers. The Range-v3 library doesn't come with a container facade, sorry.
(What's going on: since views represent indirection, view_facade
tries very hard to make const and non-const begin()
and end()
return the same types. If cursor_begin() const
is present, that one is always chosen. Always. When this breaks code, it's generally because that code is confusing containers with views.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With