C++ Ranges require certain concepts to be implemented. If user-defined container doesn't refine those, it won't be treated as Range.
Here is a working minimal example using range-v3, based on this SO answer.
| #include <iostream> | |
| #include <iterator> | |
| #include <range/v3/all.hpp> | |
| struct Test { | |
| struct iterator; | |
| struct sentinel; | |
| int counter; | |
| Test() = default; | |
| iterator begin(); | |
| sentinel end(); | |
| // These are not required. | |
| // sentinel end() const; | |
| // iterator begin() const; | |
| }; | |
| struct Test::iterator { | |
| using value_type = int; | |
| using reference = int&; | |
| using pointer = int*; | |
| using iterator_category = std::input_iterator_tag; | |
| using difference_type = ptrdiff_t; | |
| Test* test; | |
| iterator& operator++() { | |
| test->counter++; | |
| return *this; | |
| } | |
| void operator++(int) { | |
| (void)++*this; | |
| } | |
| reference operator*() { return test->counter; } | |
| std::add_const_t<reference> operator*() const { return test->counter; } | |
| bool operator!=(const iterator& rhs) const { return rhs.test != test; } | |
| bool operator!=(const sentinel&) const { return true; } | |
| template <typename T> | |
| bool operator==(T&& t) const { return !(*this != std::forward<T>(t)); } | |
| }; | |
| struct Test::sentinel { | |
| bool operator!=(const iterator& iterator) const { | |
| return iterator != *this; | |
| } | |
| // This is not required: | |
| // bool operator!=(const sentinel&) { | |
| // return true; | |
| // } | |
| template <typename T> | |
| bool operator==(T&& t) const { return !(*this != std::forward<T>(t)); } | |
| }; | |
| Test::iterator Test::begin() { return {this}; } | |
| Test::sentinel Test::end() { return {}; } | |
| int main() { | |
| auto container = Test(); | |
| static_assert(std::is_same_v<decltype(container.begin() == container.end()), bool>); | |
| static_assert(std::is_same_v<decltype(container.end() == container.begin()), bool>); | |
| static_assert(ranges::range<Test&>, "It is not a range"); | |
| auto rng = container | ranges::views::take(10); | |
| for (auto n : rng) { | |
| std::cerr << n << std::endl; | |
| } | |
| return 0; | |
| } |
~/tmp/range$ g++ main.cpp -std=c++17 -Irange-v3/include -o main && ./main
0
1
2
3
4
5
6
7
8
9Tested with https://github.com/ericniebler/range-v3/tree/4b49dac2853b413440062646164cdd82866c5d16 (HEAD as of Aug 24, 2019).