#include #include #include #include #include class Fibonacci { public: // if we want read/write iterator, we can change this to: // template // class iterator_impl // and define: // using iterator = iterator_impl // using const_iterator = iterator_impl class iterator { public: using value_type = int; using reference = const int&; // this is const int&, because we defined const_iterator = iterator (const_iterator has to return readonly references) using pointer = const int*; // should be almost the same as the reference using difference_type = std::ptrdiff_t; // <- this has no meaning in our case, computing a difference is not that simple // TODO: using iterator_category = tag for bidirectional iterators // TODO default constructor (iterators have to be default-constructible) iterator(int a0, int a1) : a0_{a0}, a1_{a1} {} reference operator*() const { // for read-only iterator, we can define `reference operator*() const` return a0_; } iterator& operator++() { return *this; } // TODO: the post-increment iterator (creates a copy, increments *this, returns the copy) // TODO: implement the decrement operators // an example of defaulting the == operator: (the compiler then also creates the != version) friend bool operator==(const iterator& left, const iterator& right) = default; private: int a0_, a1_; }; using const_iterator = iterator; // TODO: using sentinel = some type that always compares unequal to iterator [[nodiscard]] Fibonacci(int a0, int a1) : a0_{a0}, a1_{a1} {} [[nodiscard]] iterator begin() const { return iterator{a0_, a1_}; } [[nodiscard]] sentinel end() const { return {}; } private: int a0_, a1_; }; // some tests: static_assert(std::bidirectional_iterator); static_assert(std::ranges::bidirectional_range);