Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Range-v3: Use view_facade to provide both const and non-const iterators

Tags:

c++

range-v3

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?

like image 292
edflanders Avatar asked Jul 15 '15 02:07

edflanders


People also ask

What is Range v3?

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.

Is Range v3 header only?

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.

What is const iterator?

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).


1 Answers

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.)

like image 161
Eric Niebler Avatar answered Nov 16 '22 02:11

Eric Niebler