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
9
Tested with https://github.com/ericniebler/range-v3/tree/4b49dac2853b413440062646164cdd82866c5d16 (HEAD as of Aug 24, 2019).