I use an API that comes with an iteration functionality using a void* handle.
void* handle = BrowseInit();
while (BrowseGetNext(handle))
{
// ...
int x = BrowseGetData(handle);
}
BrowseFree(handle);
How would I go about wrapping this into a C++11 iterator for use in range-based for-loops? Since the value of the handle doesn't actually change, I need some trickery in operator != ().
class Iterator
{
public:
friend class it;
class it
{
public:
it(Iterator* data) : _data(data) { }
bool operator != (const it& other) const
{
// what should I put in here?
}
const it& operator ++ ()
{
BrowseGetNext(_data->_handle);
}
int operator * () const
{
return BrowseGetData(_data->_handle);
}
private:
Iterator* _data;
};
Iterator() : _handle(BrowseInit()) { }
~Iterator()
{
BrowseFree(_handle);
}
it begin() const
{
return it(this);
}
it end() const
{
return it(nullptr);
}
private:
void* _handle;
};
This should work.
class Iterator
{
public:
friend class it;
class it
{
public:
// Constructor for begin().
it(Iterator* data) : _data(data), index_(0) { }
// Constructor for end().
it(Iterator* data, int) : _data(data), index_(-1) { }
bool operator != (const it& other) const
{
return !(*this == other);
}
bool operator == (const it& other) const
{
return ( this->_data == other._data && this->_index == rhs._index );
}
const it& operator ++ ()
{
// Increment the index if there's more data.
// Otherwise, set it to -1.
if ( BrowseGetNext(_data->_handle) )
{
++index_;
}
else
{
index_ = -1;
}
}
int operator * () const
{
return BrowseGetData(_data->_handle);
}
private:
Iterator* _data;
int _index;
};
Iterator() : _handle(BrowseInit()) { }
~Iterator()
{
BrowseFree(_handle);
}
it begin() const
{
return it(this);
}
it end() const
{
return it(this, 0);
}
private:
void* _handle;
};
Update: Setup iterator_traits for it
template <> struct std::iterator_traits<Iterator::it>
{
typedef int difference_type;
typedef int value_type;
typedef int* pointer;
typedef int& reference;
typedef std::forward_iterator_tag iterator_category;
};
Thanks for the suggestion, Yakk.
Update 2
Instead of specializing std::iterator for Iterator::it, derive Iterator::it from std::iterator.
class it : public std::iterator<std::forward_iterator_tag, int, int>
{
....
};
Related
This reduced test case (written following the example in the user manual) does not compile
#include <range/v3/all.hpp>
#include <vector>
using v = std::vector<int>;
class rows : public ranges::view_facade<rows> {
public:
rows() = default;
explicit rows(const v& data) : it_(data.begin()), end_(data.end()) {}
private:
friend ranges::range_access;
v::const_iterator it_;
v::const_iterator end_;
const int& read() const {
return *it_;
}
bool equal(ranges::default_sentinel) const {
return it_ == end_;
}
void next() {
++it_;
}
};
int main() {
v data{10, 20, 30, 40};
auto rng = rows(data) | ranges::view::unique;
}
The compilation fails with a static_assert since, according to view::unique, my range does not model the ForwardRange concept
But if I rewrite my class to use an explicit cursor, the compilation is successful
class rows : public ranges::view_facade<rows> {
public:
rows() = default;
explicit rows(const v& data) : data_{&data} {}
private:
friend ranges::range_access;
const v* data_;
struct cursor {
cursor() = default;
cursor(v::const_iterator iter) : it{iter} {}
const int& read() const {
return *it;
}
bool equal(const cursor& other) const {
return it == other.it;
}
void next() {
++it;
}
v::const_iterator it;
};
cursor begin_cursor() const {
return {data_->begin()};
}
cursor end_cursor() const {
return {data_->end()};
}
};
Why the first class is not a ForwardRange and the second instead is ok?
view_facade<>::(begin|end)_cursor() by default returns an instance of the derived class, so I don't understand why it does not work.
I've added a static assert to be sure that ranges::range_access::single_pass_t is false, so I suspect that the problem is related with the ForwardIterator concept.
You define equal(ranges::default_sentinel) const but not equal(const rows&), so the iterator type of your range will satisfy EqualityComparableWith<ranges::default_sentinel> but not EqualityComparable. Forward iterators (and stronger) are required to satisfy EqualityComparable, so rows satisfies InputRange but not ForwardRange.
I suggest you define:
bool equal(const rows& that) const {
return it_ == that.it_;
}
and the program behaves as you expect.
I've got this class:
template<typename T>
class Konten
{
enum { ssize = 100 };
T stack[ssize];
int top;
public:
Konten() : top(0) {}
void push(T i) {
assert(top < ssize); stack[top++] = i;
};
T pop() {
assert(top > 0); return stack[--top];
};
int rozmiar() { return top; };
class iterator {
Konten& s;
int index;
public:
iterator(Konten& is) : s(is), index(0) {};
iterator(Konten& is, bool) : s(is), index(s.top) {};
T operator++() { // Prefix
assert(index < s.top);
return s.stack[++index];
};
T operator++(int) { // Postfix
assert(index < s.top);
return s.stack[index++];
};
T& operator*() const { return s.stack[index]; };
iterator& operator=(const iterator& rv) {
s = rv.s;
index = rv.index;
return *this;
}
};
iterator begin() { return iterator(*this); };
iterator end() { return iterator(*this, true); };
friend class iterator;
};
And as you see it has another class inside it. I want to create an object of the iterator class this way:
Konten<double> pier;
iterator it1(pier);
But I keep on getting following error: "argument list for class template "iterator" is missing".
What am I doing wrong?
Your iterator needs to be declared as Konten<double>::iterator.
Consider the following class that wraps a container and type-erases its type:
class C final {
struct B {
virtual bool empty() const noexcept = 0;
};
template<class T, class A>
struct D: public B {
// several constructors aimed to
// correctly initialize the underlying container
bool empty() const noexcept override { return v.empty(); }
private:
std::vector<T, A> v;
};
// ...
public:
//...
bool operator==(const C &other) const noexcept {
// ??
// would like to compare the underlying
// container of other.b with the one
// of this->b
}
private:
// initialized somehow
B *b;
};
I'd like to add the operator== to the class C.
Internally, it should simply invoke the same operator on the underlying containers, but I'm stuck on this problem, for I don't know how to do that.
The idea is that two instances of C are equal if the operator== of their underlying containers return true.
Whatever I've tried till now, I ever ended up being unable to get the type of one of the two underlying containers, mainly the one of other.
Is there an easy solution I can't see at the moment or I should give up?
Despite the good suggestion from juanchopanza, I found that, as far as the underlying containers represent the same concept (as an example, different specializations of a vector), maybe there is no need of a type-erased iterator.
Below it's a possible implementation that relies on the operator[] and the size member method:
#include <vector>
#include <cassert>
class Clazz final {
struct BaseContainer {
virtual std::size_t size() const noexcept = 0;
virtual int operator[](std::size_t) const = 0;
virtual void push_back(int) = 0;
};
template<class Allocator>
struct Container: public BaseContainer {
Container(Allocator alloc): v{alloc} { }
std::size_t size() const noexcept override { return v.size(); }
int operator[](std::size_t pos) const override { return v[pos]; }
void push_back(int e) override { v.push_back(e); }
private:
std::vector<int, Allocator> v;
};
public:
template<class Allocator = std::allocator<int>>
Clazz(const Allocator &alloc = Allocator{})
: container{new Container<Allocator>{alloc}} { }
~Clazz() { delete container; }
void push_back(int e) { container->push_back(e); }
bool operator==(const Clazz &other) const noexcept {
const BaseContainer &cont = *container;
const BaseContainer &oCont = *(other.container);
bool ret = (cont.size() == oCont.size());
for(std::vector<int>::size_type i = 0, s = cont.size(); i < s && ret; i++) {
ret = (cont[i] == oCont[i]);
}
return ret;
}
bool operator!=(const Clazz &other) const noexcept {
return !(*this == other);
}
private:
BaseContainer *container;
};
int main() {
Clazz c1{}, c2{}, c3{};
c1.push_back(42);
c2.push_back(42);
assert(c1 == c2);
assert(c1 != c3);
}
Open to criticism, hoping this answer can help other users. :-)
Assuming you wish to return false when the comparing two different containers, this should do the job (caution: untested):
class Container
{
struct Concept
{
virtual ~Concept() = default;
virtual Concept* clone() const = 0;
virtual bool equals(Concept const*) const = 0;
};
template<typename T>
struct Model final : Concept
{
Model(T t) : data{std::move(t)} {}
Model* clone() const override { return new Model{*this}; }
virtual bool equals(Concept const* rhs) const override
{
if (typeid(*this) != typeid(*rhs))
return false;
return data == static_cast<Model const*>(rhs)->data;
}
T data;
};
std::unique_ptr<Concept> object;
public:
template<typename T>
Container(T t) : object(new Model<T>{std::move(t)}) {}
Container(Container const& that) : object{that.object->clone()} {}
Container(Container&& that) = default;
Container& operator=(Container that)
{ object = std::move(that.object); return *this; }
friend bool operator==(Container const& lhs, Container const& rhs)
{ return lhs.object->equals(rhs.object.get()); }
};
I implemented a trivial class MyClass that has an array allocated with new inside it (I know that I could use a STL container, but I'm trying to understand how they work). I also created an iterator subclass, able to iterate on all the elements of a MyClass object:
class MyIterator : public iterator<forward_iterator_tag,int>
{
private:
int* data= nullptr;
int length;
int pointer=0;
int nullvalue=0;
public:
MyIterator(int* data, int length, bool end= false)
{
this->data= data;
this->length= length;
if(end)
pointer=-1;
}
~MyIterator()
{
delete[] data;
}
MyIterator& operator++()
{
if(pointer!= length-1)
{
pointer++;
}
else
{
pointer= -1;
}
return *this;
}
bool operator==(const MyIterator& other)
{
return pointer==other.pointer;
}
bool operator!=(const MyIterator& other)
{
return pointer!= other.pointer;
}
int& operator* ()
{
if(pointer==-1)
return nullvalue;
else
return data[pointer];
}
};
class MyClass
{
private:
int* data= nullptr;
int length= 100;
public:
MyClass()
{
data= new int[length];
for(int i=0; i<length;i++)
data[i]=i+1;
}
iterator<forward_iterator_tag,int> begin()
{
return MyIterator(data,length);
}
iterator<forward_iterator_tag,int> end()
{
return MyIterator(data,length,true);
}
};
While the iterator works if I use it this way:
for(MyIterator i= MyClass_instance.begin(); i!=MyClass_instance.end();i++) {...}
It doesn't work if I try to use it with BOOST_FOREACH:
BOOST_FOREACH(int i, MyClass_instance) {...}
These are the errors that I get:
You're slicing your iterator by returning them as std::iterator<> by value. You cannot do that.
Returning by reference would avoid the slicing problem but introduces a worse problem: it returns a reference to a temporary¹.
Hence, fix it by returning your actual iterator type by value.
Your type was missing a const iterator.
All the iterator members weren't const-correct.
Also, according to the page Extensibility it looks like you need to add
namespace boost {
template<> struct range_mutable_iterator<MyClass> {
typedef MyClass::MyIterator type;
};
template<> struct range_const_iterator<MyClass> {
typedef MyClass::MyConstIterator type;
};
}
There is serious trouble with the Rule-Of-Three implementation for your iterator type (What is The Rule of Three?).
You're deleting the container's data every time an iterator goes out of existence. And MyClass itself never frees the data...
Fixing most (?) of the above:
Live On Coliru
#include <iterator>
#include <boost/foreach.hpp>
class MyClass
{
private:
int* data = nullptr;
int length = 100;
public:
class MyIterator : public std::iterator<std::forward_iterator_tag, int>
{
public:
MyIterator(int* data, int length, bool end = false)
{
this->data= data;
this->length= length;
if(end)
pointer=-1;
}
MyIterator& operator++()
{
if(pointer!= length-1) {
pointer++;
}
else {
pointer= -1;
}
return *this;
}
bool operator==(const MyIterator& other) const { return pointer==other.pointer; }
bool operator!=(const MyIterator& other) const { return pointer!= other.pointer; }
int& operator*() const
{
if(pointer==-1)
return nullvalue;
else
return data[pointer];
}
private:
value_type* data = nullptr;
int length;
int pointer = 0;
mutable value_type nullvalue = 0;
};
class MyConstIterator : public std::iterator<std::forward_iterator_tag, const int>
{
public:
MyConstIterator(int const* data, int length, bool end = false)
{
this->data= data;
this->length= length;
if(end)
pointer=-1;
}
MyConstIterator& operator++()
{
if(pointer!= length-1) {
pointer++;
}
else {
pointer= -1;
}
return *this;
}
bool operator==(const MyConstIterator& other) const { return pointer==other.pointer; }
bool operator!=(const MyConstIterator& other) const { return pointer!= other.pointer; }
int const& operator*() const
{
if(pointer==-1)
return nullvalue;
else
return data[pointer];
}
private:
value_type* data = nullptr;
int length;
int pointer = 0;
value_type nullvalue = 0;
};
public:
typedef MyIterator iterator_type;
typedef MyConstIterator const_iterator_type;
MyClass()
{
data= new int[length];
for(int i=0; i<length;i++)
data[i]=i+1;
}
~MyClass() {
delete[] data;
}
iterator_type begin() { return MyIterator(data,length); }
iterator_type end() { return MyIterator(data,length,true); }
const_iterator_type begin() const { return MyConstIterator(data,length); }
const_iterator_type end() const { return MyConstIterator(data,length,true); }
};
namespace boost {
template<> struct range_mutable_iterator<MyClass> {
typedef MyClass::MyIterator type;
};
template<> struct range_const_iterator<MyClass> {
typedef MyClass::MyConstIterator type;
};
}
#include <iostream>
int main()
{
MyClass c;
BOOST_FOREACH(int i, c) {
std::cout << i << "\n";
}
}
¹ (unless you store the iterators somewhere else, but that would be a huge anti-pattern for many many reasons)
I have two iterators, both derive from boost::iterator_facade (but not from each other) and I want to be able to compare them because I don't want to have more end() methods when one is sufficient. Is it possible?
The following minimal example is not working for me, but I think it should. What am I doing wrong?
#include <vector>
#include <iostream>
#include <boost/iterator/iterator_facade.hpp>
using namespace std;
typedef vector<int> val_type;
typedef vector<val_type> vec_type;
class myiterator
: public boost::iterator_facade<
myiterator
, val_type
, boost::forward_traversal_tag
>
{
private:
friend class boost::iterator_core_access;
friend class base_myiterator;
public:
explicit myiterator(vec_type::iterator _it)
: it(_it)
{}
myiterator(myiterator const& other)
: it(other.it)
{}
private:
void increment() { ++it; }
bool equal(myiterator const& other) const
{
return (it == other.it);
}
val_type& dereference() const { return *it; }
vec_type::iterator it;
};
class base_myiterator
: public boost::iterator_facade<
base_myiterator
, val_type
, boost::forward_traversal_tag
>
{
private:
friend class boost::iterator_core_access;
public:
explicit base_myiterator(vec_type::const_iterator _it, val_type _base)
: base(_base),
it(_it)
{
idx.resize(base.size());
}
base_myiterator(base_myiterator const& other)
: base(other.base),
it(other.it)
{
idx.resize(base.size());
}
private:
void increment()
{
++it;
for (size_t i=0; i<base.size(); ++i)
{
idx[i] = base[i] + (*it)[i];
}
}
bool equal(base_myiterator const& other) const
{
return (it == other.it);
}
bool equal(myiterator const& other) const
{
return (it == other.it);
}
val_type const& dereference() const
{
return idx;
}
val_type base;
vec_type::const_iterator it;
val_type idx;
};
struct Sample
{
vec_type vec;
myiterator begin()
{
return myiterator(vec.begin());
}
base_myiterator begin(val_type const& base)
{
return base_myiterator(vec.begin(), base);
}
myiterator end()
{
return myiterator(vec.end());
}
};
int main ()
{
Sample s;
val_type val;
val.push_back(1); val.push_back(0);
s.vec.push_back(val);
val.clear(); val.push_back(0); val.push_back(1);
s.vec.push_back(val);
val.clear(); val.push_back(-5); val.push_back(5);
//for (myiterator it=s.begin(); it!=s.end(); ++it)
for (base_myiterator it=s.begin(val); it!=s.end(); ++it)
{
cout << (*it)[0] << " " << (*it)[1] << endl;
}
}
boost::iterator_facade checks if two iterators are interoperable before instantiating the relation operators.
It uses boost::type_traits::is_convertible to check if it is legal to convert one type of iterator into the other type. Thus if you add a constructor base_myiterator(myiterator const& other) it will work. It will use the special equal overload you provided and not do any conversion (i.e. the additional copy constructor won't be used, it just needs to be there).
Furthermore, the base_myiterator seems to operate as some sort of const_iterator (val_type const& reference() const). In this case you should pass val_type const as template parameter Value to iterator_facade as described here.