How can I implement random access iterators for my container? - c++

This is the header file for the container including a try to implement random access iterators :
using namespace std;
template <class Element, class Compare = std::equal_to<Element>>
class UniqueArray {
public:
Element** data;
unsigned int curr_size;
unsigned int max_size;
int* availability_array;
explicit UniqueArray(unsigned int size);
UniqueArray(const UniqueArray& other);
~UniqueArray();
// UniqueArray& operator=(const UniqueArray&) = delete;
unsigned int insert(const Element& element);
bool getIndex(const Element& element, unsigned int& index) const;
const Element* operator[] (const Element& element) const;
bool remove(const Element& element);
unsigned int getCount() const;
unsigned int getSize() const;
class Filter {
public:
virtual bool operator() (const Element&) const = 0;
};
UniqueArray filter(const Filter& f) const;
class UniqueArrayIsFullException{};
typedef Element ua_iterator;
typedef const Element ua_const_iterator;
ua_iterator begin(){
return **data;
}
ua_const_iterator begin() const {
return **data;
}
ua_iterator end(){
return *(*data + max_size);
}
ua_const_iterator end() const {
return *(*data + max_size);
}
};
A summary of the errors I get :
error: no match for ‘operator++’
error: no match for ‘operator*’
error: no type named ‘value_type’ in ‘struct std::iterator_traits<MtmParkingLot::Vehicle>
error: no match for ‘operator!=’
error: no match for ‘operator-’
On my implementation Element gets Vehicle and all these missing operators refer to Vehicle
I'm not quite sure on how to work on these errors because for example substracting Vehicles makes no sense..

If you want an iterator to return a reference to an object when it is dereferenced, you have to define a special Iterator class to do it. With boost::indirect_iterator this is pretty simple:
#include <boost/iterator/indirect_iterator.hpp>
template <class Element, class Compare = std::equal_to<Element>>
class UniqueArray {
// ...
auto begin() {
return boost::indirect_iterator<Element**, Element>(data_);
}
auto end() {
return boost::indirect_iterator<Element**, Element>(data_ + curr_size);
}
};
Simple demo
If you want to code it yourself, the idea is:
template<class Element>
class UniqueArray {
public:
//...
class Iterator {
public:
using iterator_category = std::random_access_iterator_tag;
using value_type = Element;
using reference = Element&;
// ...
Iterator(Element** d) : data(d) { }
reference operator*() {
return **data;
}
Iterator& operator++() {
++data;
return *this;
}
friend bool operator!=(Iterator it1, Iterator it2) {
return it1.data != it2.data;
}
// ...
private:
Element** data;
};
Iterator begin() {
return Iterator(data);
}
Iterator end() {
return Iterator(data + curr_size);
}
};
Note, the full random access iterator requires implementation of many other member and non-member functions. You might want to make it a forward iterator to simplify things a little bit.
Simple demo

If you write that without the type aliases, you get definitions like
Element begin(){
return **data;
}
and use like
UniqueArray<Vehicle>::ua_iterator it = something.begin();
it++;
becomes
Vehicle it = something.begin();
it++;
which makes the cause of the errors more obvious - you're trying to apply iterator operations to your element type.
If you're fine with iteration producing Element*, the simple solution is
typedef Element** ua_iterator;
ua_iterator begin(){
return data;
}
ua_iterator end(){
return data + curr_size;
}
and similar for the const versions.
Then you could write
UniqueArray<Vehicle>::ua_iterator it = something.begin();
Vehicle* v = *it;
If you want iteration to produce Element&, you need to write an iterator class with the appropriate overloads and traits.
It's not very difficult, but it gets tedious.

Related

random_access_iterator does not convert to input_iterator in std::any_if

the code below is an adoption from here and implements a user-defined random access iterator for a class holding a dynamic array in a shared pointer. In member function any the std::any_if, which requires an input_iterator, is called. From my knowledge and comments here using a random_access_iterator instead of an input_iterator should be perfectly legal. Unfortunately it does not compile with g++ and clang++ with the error message:
In file included from iterator.cpp:1:
In file included from /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/11.1.0/../../../../include/c++/11.1.0/iostream:39:
In file included from /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/11.1.0/../../../../include/c++/11.1.0/ostream:38:
In file included from /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/11.1.0/../../../../include/c++/11.1.0/ios:40:
In file included from /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/11.1.0/../../../../include/c++/11.1.0/bits/char_traits.h:39:
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/11.1.0/../../../../include/c++/11.1.0/bits/stl_algobase.h:2065:25: error: invalid operands to binary expression ('xx<long long>::Iterator' and 'xx<long long>::Iterator')
__trip_count = (__last - __first) >> 2;
It compiles when the iterator category is changed to input_iterator.
Any ideas about the root of the problem are highly appreciated.
#include <iostream>
#include <iterator>
#include <algorithm>
#include <memory>
using namespace std;
template <typename T>
class xx{
struct Iterator
{
using iterator_category = std::random_access_iterator_tag;
//using iterator_category = std::input_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = T;
using pointer = T*;
using reference = T&;
Iterator(pointer ptr) : m_ptr(ptr) {}
reference operator*() const { return *m_ptr; }
pointer operator->() { return m_ptr; }
Iterator& operator++() { m_ptr++; return *this; }
Iterator operator++(int) { Iterator tmp = *this; ++(*this); return tmp; }
friend bool operator== (const Iterator& a, const Iterator& b) { return a.m_ptr == b.m_ptr; };
friend bool operator!= (const Iterator& a, const Iterator& b) { return a.m_ptr != b.m_ptr; };
private:
pointer m_ptr;
};
protected:
std::shared_ptr<T[]> m_data;
int n=0;
public:
xx()=default;
xx(int n):n{n}{m_data=shared_ptr<T[]>(new T[n]);};
~xx(){};
Iterator begin() { return Iterator(&m_data.get()[0]); }
Iterator end() { return Iterator(&m_data.get()[n]); }
const int sz()const{return(n);}
void any(xx<long long int> &id){
if(any_of(id.begin(),id.end(),[this](long long int i){return(i<0 || i>(this->sz()-1));})){
std::string msg="error";throw msg;
}
}
};
int main(){
xx<double> x(10);int i=0;
xx<long long int> y(5);
cout<<x.sz()<<endl;
for(auto s=x.begin();s!=x.end();++s){
*s=(double)i++;
}
i=0;
for(auto s=y.begin();s!=y.end();++s){
*s=i++;
}
for(auto i : x){
cout<<i<<endl;
}
x.any(y);
return(0);
}
A random access iterator is one that (a) has the random access iterator tag, and (b) fullfills the requirements of being a random access iterator.
Yours fails on (b).
You need to implement [] - and + and related and < etc. And obey the other rules and requirements with them.
The tag determines which implementation your iterator is dispatched to; yours fails to provide expected features for the iterator category you claim to have, so it breaks.
The standard states that lying about your iterator category means passing your iterator in makes your program ill formed, no diagnostic required. In this case, an optimized implementation that works faster on random access iterators exists, but breaks on your lie.

How to convert an iterator-like that has a `next()` methode to a regular `begin`/`end` iterator pair?

In the codebase I inherited, there is a class that look like an iterator (this isn’t the exact code, but the logic is similar).
template <class T>
struct IteratorLike {
T* next() &; // either return a pointer to a valid value or nullptr
};
The way you use it is very similar to the way you use Rust iterators:
IteratorLike<...> it = ...;
while(auto* item = it.next()) {
do_something(*item);
}
How do I convert it to make it compatible with C++ range-based for loop, algorithms, or range-v3? I’m using C++14 (gcc5.5 to be more precise), so I can’t have a sentinel type that is different from the type of the iterator itself.
So far it seems that the easiest way is to store both the iterator and the next value in my wrapper:
template <class T>
class MyIterator {
private:
IteratorLike<T> m_iter;
T* m_value;
public:
using value_type = T;
using difference_type = std::ptrdiff_t;
using pointer = T*;
using reference = T&;
using iterator_category = std::input_iterator_tag;
reference operator*() const {
assert(m_value && "trying to read past the end of the iterator");
return *m_value;
}
pointer operator->() {
// I’m not sure the assert is needed here
assert(m_value && "trying to read past the end of the iterator");
return m_value;
}
// Prefix increment
MyIterator& operator++() {
m_value = m_iter.next();
return *this;
}
// Postfix increment
MyIterator operator++(int) {
MyIterator tmp = *this;
++(*this);
return tmp;
}
// used by `my_collection.begin()`
explicit MyIterator(IteratorLike<T> iter)
: m_iter{m_iter}
, m_value{this->self.next()}
{}
// missing operator == and operator != as well as the constructor
// used `my_collection.end()
};
However, I fail to understand what my_collection.end() should return (EDIT: I just check, I can’t default-initialize m_iter), nor how to have meaningful comparison operators.
Note: I’m basically trying to do the exact reverse of this.
Since IteratorLike isn't default constructible, but is obviously copy constructible, you could use the instance you have to construct your end() iterator too. Example:
// used by `my_collection.begin()`
explicit MyIterator(const IteratorLike<T>& iter) :
m_iter{iter},
m_value{m_iter.next()}
{}
// used by `my_collection.end()`
MyIterator(const IteratorLike<T>& iter, std::nullptr_t) :
m_iter{iter},
m_value{nullptr}
{}
bool operator!=(const MyIterator& rhs) const {
return m_value != rhs.m_value;
}
Then in my_collection:
template<typename T>
class my_collection {
public:
MyIterator<T> begin() { return MyIterator<T>{itlike}; }
MyIterator<T> end() { return {itlike, nullptr}; }
private:
IteratorLike<T> itlike;
};

Making a class iterable with iteration order depending on class implementation

I have a type that has two different implementations, using different data structures. One stores its data in a std::vector<std::unique_ptr<Data>>, the other in a 2D array Data***.
The elements are stored in a specific order, meaning that their position in the vector or 2D array matters. As such, when wanting to iterate over all data in my class, my for loops are dependent on the implementation, being basically one of the following:
for(auto& data : myClass->dataVector) { do Stuff }
for(int x = 0; x < myClass->xVals; x++) {
for(int y = 0; y < myClass->yVals; y++ {
do Stuff with myClass->dataArr[x][y]
}
}
Since the two version of my class share similarities, I want to have a proper parent class that is implemented by two inheriting classes, hopefully in a way that I can iterate over my data by simply doing something such as:
for(auto& data : myClass) { doStuff }
(notice how myClass acts as if it was a collection itself, even if it actually is just a container of a collection)
where the way and order in which this iteration works obviously depends on the implementation of the class.
How do make my class iterable in such a manner?
Lets assume you have a base with all the data, and two derived classes with traversal behavior:
class Base {
public:
std::vector<...> dataVector;
int xVals;
int yVals;
Data** dataArr;
};
Defining .begin() and .end() makes a class iterable with for_each. A simple forwarding to the vector iterators is enough for the first case:
class DerivedA : private Base {
public:
auto begin() { return this->dataVector.begin(); }
auto begin() const { return this->dataVector.begin(); }
auto end() { return this->dataVector.end(); }
auto end() const { return this->dataVector.end(); }
}
For the Data** case you will have to define a custom iterator:
class iterator {
public:
using value_type = Data;
using difference_type = std::ptrdiff_t;
using reference = Data&;
using pointer = Data*;
using iterator_category = std::forward_iterator_tag;
iterator() : m_base(), m_idx(0) { }
iterator(Base* b, std::size_t idx) : m_base(b), m_idx(idx) { }
reference operator*() const { return m_base->dataArr[m_idx / m_base->yVals][m_idx % m_base->y_vals]; }
pointer operator->() const { return &**this; }
friend iterator& operator++(iterator& rhs) { ++rhs.m_idx; return rhs; }
friend iterator operator++(iterator& lhs, int) { auto cp = lhs; ++lhs; return cp; }
friend bool operator==(iterator lhs, iterator rhs) { return lhs.m_idx == rhs.m_idx; }
friend bool operator!=(iterator lhs, iterator rhs) { return !(lhs == rhs); }
private:
Base* m_base;
std::size_t m_idx;
};
class const_iterator {
// equivalent but const. (reference = const Data& and pointer = const Data*)
// Make sure iterator is convertible to const_iterator.
};
class DerivedB : private Base {
iterator begin() { return { this, 0 }; }
const_iterator begin() const { return { this, 0 }; }
iterator end() { return { this, this->xVals*this->yVals }; }
const_iterator end() const { return { this, this->xVals*this->yVals }; }
};

Wrapping a legacy C API in C++ with write iterator support

I have a legacy C API to a container-like object (specifically, the Python C API to tuples) which I would like to wrap in a nice C++14 API, so that I can use an iterator. How should I go about implementing this?
Here's some more details. We have the following existing C API which cannot be changed:
Py_ssize_t PyTuple_GET_SIZE(PyObject *p);
PyObject* PyTuple_GET_ITEM(PyObject *p, Py_ssize_t pos);
void PyTuple_SET_ITEM(PyObject *p, Py_ssize_t pos, PyObject *o)
We want to create a class which allows you to get access to a read/write iterator on the elements in the tuple.
The forward read-only iterator is not too difficult to define. Here is what I have:
class PyTuple {
private:
PyObject* tuple;
public:
PyTuple(PyObject* tuple) : tuple(tuple) {}
class iterator {
// iterator traits
PyObject* tuple;
Py_ssize_t index;
public:
iterator(PyObject *tuple, Py_ssize_t index) : tuple(tuple), index(index) {}
iterator& operator++() { index++; return *this; }
iterator operator++(int) { auto r = *this; ++(*this); return r; }
bool operator==(iterator other) const { return tuple == other.tuple && index == other.index; }
bool operator!=(iterator other) const { return !(*this == other); }
PyObject* operator*() { return PyTuple_GET_ITEM(tuple, index); }
// iterator traits
using difference_type = Py_ssize_t;
using value_type = PyObject*;
using pointer = PyObject**;
using reference = PyObject*&;
using iterator_category = std::forward_iterator_tag;
};
iterator begin() {
return iterator(tuple, 0);
}
iterator end() {
return iterator(tuple, PyTuple_GET_SIZE(tuple));
}
}
However, I am not too sure how to support writes. I have to somehow make *it = pyobj_ptr work. Conventionally, this would be done by changing the type to PyObject*& operator*() (so that it gives an lvalue) but I can't do this because the tuple "write" needs to go through PyTuple_SET_ITEM. I have heard that you can use operator= to solve this case but I am not sure if I should use a universal reference (Why no emplacement iterators in C++11 or C++14?) or a proxy class (What is Proxy Class in C++), and am not exactly sure what the code should look like exactly.
What you're looking for is basically a proxy reference. You don't want to dereference into PyObject*, you want to dereference into something that itself can give you a PyObject*. This is similar to how the iterators for types like vector<bool> behave.
Basically, you want operator*() to give you something like:
class PyObjectProxy {
public:
// constructors, etc.
// read access
operator PyObject*() const { return PyTuple_GET_ITEM(tuple, index); }
// write access
void operator=(PyObject* o) {
PyTuple_SET_ITEM(tuple, index, o); // I'm guessing here
}
private:
PyObject* tuple;
Py_ssize_t index;
};

How to define iterator for a special case in order to use it in a for loop using the auto keyword

I would like to define the subsequent code in order to be able to use it like
"for (auto x:c0){ printf("%i ",x); }"
But I do not understand something and i have searched it for some time.
The error I get is:
error: invalid type argument of unary ‘*’ (have ‘CC::iterator {aka int}’)
#include <stdio.h>
class CC{
int a[0x20];
public: typedef int iterator;
public: iterator begin(){return (iterator)0;}
public: iterator end(){return (iterator)0x20;}
public: int& operator*(iterator i){return this->a[(int)i];}
} ;
int main(int argc, char **argv)
{ class CC c0;
for (auto x:c0){
printf("%i ",x);
}
printf("\n");
return 0;
}
It seems you are trying to use int as you iterator type using the member operator*() as the deference operations. That won't work:
The operator*() you defined is a binary operator (multiplication) rather than a unary dereference operation.
You can't overload operators for built-in types and an iterator type needs to have a dereference operator.
To be able to use the range-based for you'll need to create a forward iterator type which needs a couple of operations:
Life-time management, i.e., copy constructor, copy assignment, and destruction (typically the generated ones are sufficient).
Positioning, i.e., operator++() and operator++(int).
Value access, i.e., operator*() and potentially operator->().
Validity check, i.e., operator==() and operator!=().
Something like this should be sufficient:
class custom_iterator {
int* array;
int index;
public:
typedef int value_type;
typedef std::size_t size_type;
custom_iterator(int* array, int index): array(array), index(index) {}
int& operator*() { return this->array[this->index]; }
int const& operator*() const { return this->array[this->index]; }
custom_iterator& operator++() {
++this->index;
return *this;
}
custom_iterator operator++(int) {
custom_iterator rc(*this);
this->operator++();
return rc;
}
bool operator== (custom_iterator const& other) const {
return this->index = other.index;
}
bool operator!= (custom_iteartor const& other) const {
return !(*this == other);
}
};
You begin() and end() methods would then return a suitably constructed version of this iterator. You may want to hook the iterator up with suitable std::iterator_traits<...> but I don't think these are required for use with range-based for.
Dietmar Kühl explained well why your code does not work: you cannot make int behaving as an iterator.
For the given case, a suitable iterator can be defined as a pointer to int. The following code is tested at ideone:
#include <stdio.h>
class CC{
int a[0x20];
public: typedef int* iterator;
public: iterator begin() {return a;}
public: iterator end() {return a+0x20;}
} ;
int main(int argc, char **argv)
{
class CC c0;
int i = 0;
for (auto& x:c0){
x = ++i;
}
for (auto x:c0){
printf("%i ",x);
}
printf("\n");
return 0;
}