22

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())); 
sdgfsdh
  • 33,689
  • 26
  • 132
  • 245

3 Answers3

17

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()));
Toby Speight
  • 27,591
  • 48
  • 66
  • 103
Brian Rodriguez
  • 4,250
  • 1
  • 16
  • 37
  • 4
    The documentation for `iterator_range` lives [here](https://ericniebler.github.io/range-v3/structranges_1_1v3_1_1iterator__range.html). Just call `ranges::make_iterator_range(x.err_begin(), x.err_end())`. – Eric Niebler Dec 21 '16 at 17:29
  • I cannot find `iterator_range` and `make_iterator_range` from the code anymore. Have they been renamed? – kaba Mar 13 '17 at 23:00
  • @EricNiebler, why do we need `iterator_range`, while we can simply create a `range` of iterators?.. – Mikhail Mar 18 '18 at 16:27
  • 1
    Ah, are you using the Microsoft fork of range-v3 for MSVC? In that (very out-of-date) fork, `iterator_range` was called `range`. It isn't any longer. – Eric Niebler Mar 19 '18 at 20:25
  • 4
    For future readers: in C++20 `std::ranges::subrange` seems to have replace `ranges:make_iterator_range`. – Werner Henze Jul 26 '21 at 21:16
4

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

Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148
  • 3
    This type is not [Regular](http://stackoverflow.com/a/14000046/195873). It will not play nicely with the rest of the range-v3 library. Brian's answer below is the correct answer. (I'm the author of range-v3, FWIW.) – Eric Niebler Dec 21 '16 at 22:45
0

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;
}
Richard Hodges
  • 68,278
  • 7
  • 90
  • 142