How do I create a range from a begin and end iterator?

5.1k views Asked by At

I have an object with functions for getting the begin and end iterators:

const_iterator err_begin() const
const_iterator err_end() const 

Because they are not named begin and end, I cannot pass my object directly to functions in range-v3.

Is there a simple wrapper I can use to make this object work with the range-v3 library?

For example:

auto hasErrors = !empty(something(x.err_begin(), x.err_end())); 
3

There are 3 answers

5
Brian Rodriguez On BEST ANSWER

In C++20 onwards, you're looking for subrange:

auto hasErrors = !empty(std::ranges::subrange{x.err_begin(), x.err_end()});

If you're still using Ranges-v3, you'll want iterator_range:

auto hasErrors = !empty(ranges::make_iterator_range(x.err_begin(), x.err_end()));
1
Sam Varshavchik On

You clarified that the class in question is part of a library that you cannot change. Fine. Create a facade class:

class FacadeClass {

      const RealClassWithErrBeginEnd &r;

public:

      FacadeClass(const RealClassWithErrBeginEnd &r) : r(r) {}

      auto begin() const { return r.err_begin(); }
      auto end() const { return r.err_end(); }
};

This should be good enough to fool most code that expects a container. In the worst case, you might need to provide additional typedefs in the facade, i.e. value_type, etc...

0
Richard Hodges On

boost::make_iterator_range will do the right thing. Now add a little ADL and we find that one free function solves all our problems:

#include <vector>
#include <iostream>
#include <string>
#include <boost/range.hpp>


// simulate the library class
struct X
{
    auto err_begin() const { return errors.begin(); }
    auto err_end() const { return errors.end(); }

    std::vector<std::string> errors;

};

// provide a generator to build an iterator range
auto errors(const X& x)
{
    return boost::make_iterator_range(x.err_begin(), x.err_end());
}

// do things with the iterator_range
int main()
{
    X x;
    for (const auto& err : errors(x))
    {
        std::cout << err << std::endl;
    }

    std::cout << empty(errors(x)) << std::endl;
}