1

I am trying to convert my range (pair of iterators) to iterator_range so that I can take advantage of all the views and actions. I am able to convert my range to boost::iterator_range, but am getting a compilation failure when converting to range::v3. Here is a minimal example:

struct MyRange
{
    struct iterator_t : std::iterator<std::input_iterator_tag, int>
    {
        friend bool operator==(const iterator_t& lhs, const iterator_t& rhs);
        friend bool operator!=(const iterator_t& lhs, const iterator_t& rhs);
    };
    iterator_t begin() { return iterator_t{}; };
    iterator_t end() { return iterator_t{}; };
};

int main(int argc, char *argv[])
{
    auto my_range    = MyRange{};
    auto boost_range = boost::make_iterator_range(my_range.begin(), my_range.end()); // works
    auto v3_range    = ranges::v3::make_iterator_range(my_range.begin(), my_range.end()); // doesn't compile
}

It looks like I need to do something to satisfy the Sentinel concept of the iterator_range, but I haven't been able to figure out what. Any help is appreciated!

Edit: I am compiling with gcc54 -std=c++14. range v3/c++ compilations errors are kind of long, but here is a snippet:

range-v3/include/range/v3/iterator_range.hpp:171:17: note: in expansion of macro 'CONCEPT_REQUIRES_'
             CONCEPT_REQUIRES_(Sentinel<S, I>())>
             ^
range-v3/include/range/v3/utility/concepts.hpp:669:15: note: invalid template non-type parameter
 >::type = 0                                                                     \
           ^
range-v3/include/range/v3/iterator_range.hpp:171:17: note: in expansion of macro 'CONCEPT_REQUIRES_'
             CONCEPT_REQUIRES_(Sentinel<S, I>())>
skgbanga
  • 2,477
  • 2
  • 20
  • 29
  • What compilation failure are you getting? – cdhowie Mar 28 '17 at 19:19
  • @cdhowie Edited with a snippet of the compilation error. – skgbanga Mar 28 '17 at 19:26
  • For an iterator value `i`, the expressions `*i` and `++i` must be well-formed (though actually evaluating these expressions may not be, for example, for past-the-end iterator values). Adding these operators to your `iterator_t` type might permit compilation. You may also need to specialize `std::iterator_traits` for your type `MyRange::iterator_t`. – cdhowie Mar 28 '17 at 19:40
  • I think that is not the reason. e.g. http://coliru.stacked-crooked.com/a/f3f761128e23bc1b in this, I added ``*i`` and ``++i``, but it still doesn't compile. Also boost version compiles fine (even without these). I think we are missing something here. – skgbanga Mar 28 '17 at 20:00
  • It doesn't compile in that example because of `error: no member named 'make_iterator_range' in namespace 'ranges::v3'; did you mean 'boost::make_iterator_range'?`, not because of anything having to do with `MyRange::iterator_t`. – cdhowie Mar 28 '17 at 20:12
  • @cdhowie that's because I couldn't find an online compiler that has range v3 headers in its include path. :) – skgbanga Mar 28 '17 at 20:20
  • Well then, linking to coliru doesn't really accomplish much... Check out the [Sentinel](https://ericniebler.github.io/range-v3/structranges_1_1v3_1_1concepts_1_1_sentinel.html) docs. This concept is composed of some other concepts. Likely there is something missing. – cdhowie Mar 28 '17 at 20:26
  • In particular, `WeaklyIncrementable` requires that the difference type of your iterator passes `std::is_integral`. I'm not 100% sure where it's trying to obtain this type, but my guess is `std::iterator_traits::difference_type`. – cdhowie Mar 28 '17 at 20:30
  • It looks like it is looking for [`MyRange::iterator_t::difference_type`](https://github.com/ericniebler/range-v3/blob/master/include/range/v3/utility/associated_types.hpp#L61) to be defined. My guess is it will also want an `operator-` returning `difference_type` for obtaining the difference between iterators. – cdhowie Mar 28 '17 at 20:39
  • If you make your `iterator` actually satisfy the iterator requirements, then your range will satisfy the range requirements and you won't *need* `make_iterator_range`. – Casey Mar 28 '17 at 20:42
  • @Casey The ``iterator`` requirements mentioned over here: http://en.cppreference.com/w/cpp/concept/Iterator don't require much. And the coliru link: http://coliru.stacked-crooked.com/a/090f4b56b47b88ef (shown just for the code, not for compilation!) satisfy all the requirements. (atleast I think so). And I think iterator_range provides nice aliases/typedefs that certain algorithms require. – skgbanga Mar 28 '17 at 20:52
  • 1
    Your iterator (a) doesn't have a post-increment operator (`operator++(int)`), and (b) has a non-`const` `operator*`. And no, I assure you that `iterator_range` is simply a range like any other with no special qualities. Its purpose is to provide a mechanism for forming a range when you have an iterator and sentinel. – Casey Mar 28 '17 at 21:57
  • 1
    See http://coliru.stacked-crooked.com/a/71eca3161805edfb. (Coliru has an ancient range-v3, from the dark ages when `iterator_range` and `make_iterator_range` were named `range` and `make_range`.) – Casey Mar 28 '17 at 21:58
  • wow! Thanks! I think we certainly need better error messages for these. Do you want to officially answer this question, and i can mark it as the correct answer. – skgbanga Mar 29 '17 at 00:41

1 Answers1

2

Your iterator is not an iterator. It's doesn't have dereference, pre- or post-increment.

auto my_range    = MyRange{};
auto i           = my_range.begin();
*i;
++i;
i++;

causes:

prog.cc: In function 'int main()':
prog.cc:20:5: error: no match for 'operator*' (operand type is 'MyRange::iterator_t')
     *i;
     ^~
prog.cc:21:5: error: no match for 'operator++' (operand type is 'MyRange::iterator_t')
     ++i;
     ^~~
prog.cc:22:6: error: no 'operator++(int)' declared for postfix '++' [-fpermissive]
     i++;
     ~^~
Eric Niebler
  • 5,927
  • 2
  • 29
  • 43