I'm writing a class which will iterate over a set of handles. Basically I'm working against a bunch of C functions which implement the following interface:
SomeHandle getFirst(ParentHandle);
SomeHandle getNext(SomeHandle);
Here is my iterator's interface and its partial implementation. I need an interface so that I can Mock this iterator for the purposes of TDD.
template<class HandleT>
class IHandleIterator
{
public:
virtual void operator++() = 0;
virtual const HandleT& operator*() const = 0;
};
template<class HandleT>
class HandleIterator : public IHandleIterator<HandleT>
{
public:
// used by something.end()
HandleIterator() : _isLast(true)
{
}
// updates _isLast when the end is reached
virtual void operator++()
{
}
virtual const HandleT& operator*() const
{
return _currentHandle;
}
protected:
HandleT _currentHandle;
bool _isLast;
};
What I want to do is add operator!= to the interface to test when I've reached the end of what I'm iterating over, as follows:
for(IHandleIterator i=something.begin(); i!=seomething.end(); i++)
{
*i;
}
However I can't figure out how to do this. Can anyone offer me suggestions?
If I can't find a solution involving operator!= then I'm wondering if this is a good approach:
class IHandleIterator
{
public:
virtual void operator++() = 0;
virtual const HandleT& operator*() const = 0;
virtual bool isLast const = 0;
};
for(IHandleIterator i=something.begin(); !i.isLast(); i++)
{
*i;
}
What do you think?
Related
Edit: I had copied the base template for the statisticscompiler class from another solution, and it seems I somehow had ended up editing the original one while including the new one (that hadn't been edited yet) which is what led to the errors. So a tale of caution against copy pasting code into another file with the same name.
I will just post the header files because I think that's what matters here, let me know if otherwise and I can post the cpp. I have one base class that collects statistics from a process, with two derived classes and then a class that let's me use several statistics classes at once
Statistics.h
#pragma once
#define STATISTIC_H
#include <vector>
#include "Arrays.h"
class Statistics
{
public:
Statistics() {}
virtual void DumpOnePath(MJArray results) = 0;
virtual std::vector<std::vector<double>> GetResultsSoFar() const = 0;
virtual Statistics* clone() const = 0;
virtual ~Statistics() {}
private:
};
class StatisticsMean : public Statistics
{
public:
StatisticsMean();
virtual void DumpOnePath(MJArray results) ;
virtual std::vector<std::vector<double>> GetResultsSoFar() const ;
virtual Statistics* clone() const;
private:
MJArray RunningSums;
unsigned long PathsDone;
};
class StatisticsQuantiles : public Statistics
{
public:
StatisticsQuantiles(double p_lower_, double p_upper_);
virtual void DumpOnePath(MJArray results);
virtual std::vector<std::vector<double>> GetResultsSoFar() const;
virtual Statistics* clone() const;
private:
std::vector<MJArray> RunningResults;
unsigned long PathsDone;
double p_lower;
double p_upper;
};
StatisticsCompiler.h
#pragma once
#define STATISTICS_COMPILER_H
#include "statistics.h"
#include "wrapper.h"
class StatisticsCompiler : public Statistics
{
public:
StatisticsCompiler(const std::vector <Wrapper<Statistics>>& Inner_);
virtual Statistics* clone() const;
virtual void DumpOnePath(MJArray results);
virtual std::vector<std::vector<double>> GetResultsSoFar() const;
private:
std::vector <Wrapper<Statistics>> Inner;
};
And in my main class I'm trying to do this:
StatisticsMean meanGatherer;
StatisticsQuantiles quantileGatherer(p_lower, p_upper);
vector<Wrapper<Statistics>> gathererArray{ meanGatherer, quantileGatherer};
StatisticsCompiler meanAndQuantileGatherer(gathererArray);
Which gives an error no the last line complaining that "No instance of constructor matches the argument list. Argument types are:
(std::vector<Wrapper<Statistics>, std::allocator<Wrapper<Statistics>>>)."
But isn't that exactly what I've defined the constructor to accept? at least the first part, I don't know what
std::allocator<Wrapper<Statistics>>
means.
Wrapper.h in case needed. It does the memory handling
#pragma once
#define WRAPPER_H
template< class T>
class Wrapper
{
public:
Wrapper()
{
DataPtr = 0;
}
Wrapper(const T& inner)
{
DataPtr = inner.clone();
}
~Wrapper()
{
if (DataPtr != 0)
delete DataPtr;
}
Wrapper(const Wrapper<T>& original)
{
if (original.DataPtr != 0)
DataPtr = original.DataPtr->clone();
else
DataPtr = 0;
}
Wrapper& operator=(const Wrapper<T>& original)
{
if (this != &original)
{
if (DataPtr != 0) {
delete DataPtr;
}
DataPtr = (original.DataPtr != 0) ? original.DataPtr->clone() : 0;
}
return *this;
}
T& operator*()
{
return *DataPtr;
}
const T& operator*() const
{
return *DataPtr;
}
const T* const operator->() const
{
return DataPtr;
}
T* operator->()
{
return DataPtr;
}
private:
T* DataPtr;
};
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()); }
};
Apologies that this is pretty long, but I couldn't figure out how to make it shorter and still show the important features of my problem.
I'm asking this even though I have come up with an idea of how to do what I want, but it requires implementing an iterator in a way that doesn't match the standard iterator pattern. I would like to ask for any suggestions on how this could be done in a more standard or better way.
I have an abstract base class. Any subclass of it will have some collections of objects. There is some common code that I would like to put in the base class that needs to iterate over all of the objects in the collections. The objects in the collections will all descend from another abstract base class, but will be subclass objects. There may be multiple collections of objects from multible subclasses, and the collections may be different collection types. What I'd really like to do is something like this: (Note: this code will not compile.)
class CollectionObjectBase
{
public:
virtual int someInterface(int x) = 0;
};
class MyObjectBase
{
public:
class iterator
{
public:
virtual CollectionObjectBase& operator*() = 0;
virtual iterator& operator++() = 0;
virtual bool operator!=(iterator& other) = 0;
};
virtual iterator begin() = 0;
virtual iterator end() = 0;
int processCollections()
{
iterator it;
int sum = 0;
for(it = begin(); it != end(); ++it)
{
sum += (*it).someInterface(7);
}
return sum;
}
};
And then I want some subclasses of CollectionObjectBase and MyObjectBase like this:
class CollectionObject1 : public CollectionObjectBase { ... }
class CollectionObject2 : public CollectionObjectBase { ... }
class CollectionObject3 : public CollectionObjectBase { ... }
class MyObjectA : public MyObjectBase
{
public:
std::map<int, CollectionObject1> someThings;
std::vector< CollectionObject2> otherThings;
class iterator : public MyObjectBase::iterator
{
public:
std::map<int, CollectionObject1>::iterator it1;
std::vector< CollectionObject2>::iterator it2;
// Iterate first over it1 and then over it2.
...
};
virtual MyObjectBase::iterator begin()
{
return iterator(someThings.begin(), otherThings.begin());
}
virtual MyObjectBase::iterator end()
{
return iterator(someThings.end(), otherThings.end());
}
};
class MyObjectB : public MyObjectBase
{
public:
std::vector<CollectionObject1> someThings;
std::set< CollectionObject3> otherThings;
class iterator : public MyObjectBase::iterator
{
public:
std::vector<CollectionObject1>::iterator it1;
std::set< CollectionObject3>::iterator it2;
// Iterate first over it1 and then over it2.
...
};
virtual MyObjectBase::iterator begin()
{
return iterator(someThings.begin(), otherThings.begin());
}
virtual MyObjectBase::iterator end()
{
return iterator(someThings.end(), otherThings.end());
}
};
There are some big problems with the above code. First, MyObjectBase::begin() and MyObjectBase::end() can't return MyObjectBase::iterator because MyObjectBase::iterator is an abstract class, and you wouldn't want to anyway because you actually want a subclass of MyObjectBase::iterator that knows how to iterate over the collections in the subclass of MyObjectBase. You need to return a reference to MyObjectBase::iterator.
The second problem comes with MyObjectA::iterator::operator!=(). You'd like to do something like this:
virtual bool operator!=(iterator& other)
{
return it1 != other.it1 || it2 != other.it2;
}
But to be an overload of MyObjectBase::iterator::operator!=() it has to take a parameter of type MyObjectBase::iterator& and that doesn't have members it1 and it2. My best idea I've thought of to resolve this is to replace operator!=() with a function atEnd(), since the only thing it is being used for in this code is to detect if the iterator is at the end, but it makes it really non-standard.
Finally, MyObjectA::begin() and MyObjectA::end() cannot return a temporary. Remember, we have to return a reference to a MyObjectBase::iterator that points to a MyObjectA::iterator, not copy construct a MyObjectBase::iterator. My best idea I've thought of to resolve this is to allocate the iterator with new, and when I do that I need to return a pointer, not a reference so that the caller can delete it. So here's my final code. It works and performs the function of an iterator, but it is non-standard. Can anyone think of a way to do this with an iterator that fits the standard pattern?
#include <map>
#include <vector>
class CollectionObjectBase
{
public:
virtual int someInterface(int x) = 0;
};
class MyObjectBase
{
public:
class iterator
{
public:
virtual CollectionObjectBase& operator*() = 0;
virtual iterator& operator++() = 0;
virtual bool atEnd() = 0;
};
virtual iterator* begin() = 0;
int processCollections()
{
iterator* it;
int sum = 0;
for (it = begin(); !it->atEnd(); ++it)
{
sum += (**it).someInterface(7);
}
delete it;
return sum;
}
};
class CollectionObject1 : public CollectionObjectBase
{
public:
virtual int someInterface(int x)
{
return x + 1;
}
};
class CollectionObject2 : public CollectionObjectBase
{
public:
virtual int someInterface(int x)
{
return x + 2;
}
};
class MyObjectA : public MyObjectBase
{
public:
std::map<int, CollectionObject1> someThings;
std::vector< CollectionObject2> otherThings;
class iterator : public MyObjectBase::iterator
{
public:
std::map<int, CollectionObject1>::iterator it1;
std::map<int, CollectionObject1>::iterator it1End;
std::vector< CollectionObject2>::iterator it2;
std::vector< CollectionObject2>::iterator it2End;
iterator(std::map<int, CollectionObject1>::iterator it1Init, std::map<int, CollectionObject1>::iterator it1EndInit,
std::vector< CollectionObject2>::iterator it2Init, std::vector< CollectionObject2>::iterator it2EndInit) :
it1(it1Init),
it1End(it1EndInit),
it2(it2Init),
it2End(it2EndInit)
{
// Initialization handled by initialization list.
}
virtual CollectionObjectBase& operator*()
{
if (it1 != it1End)
{
return (*it1).second;
}
else
{
return *it2;
}
}
virtual iterator& operator++()
{
if (it1 != it1End)
{
++it1;
}
else
{
++it2;
}
return *this;
}
virtual bool atEnd()
{
return it1 == it1End && it2 == it2End;
}
};
virtual MyObjectBase::iterator* begin()
{
return new iterator(someThings.begin(), someThings.end(), otherThings.begin(), otherThings.end());
}
};
There's an issue with useless' answer. Consider these subclasses of Impl and Base:
class MyImpl : public Base::Iterator::Impl {
public:
MyImpl(std::vector<CollectionObjectSub>::iterator itInit) : it(itInit) {}
CollectionObjectBase& operator*() { return *it; }
void operator++() { ++it; }
// bool operator==(Base::Iterator::Impl const &other) const { it == other.it; }
bool operator==(MyImpl const &other) const { it == other.it; }
private:
std::vector<CollectionObjectSub>::iterator it;
};
class Sub : public Base {
public:
Iterator& begin() { return Iterator(new MyImpl(collection.begin())); }
private:
std::vector<CollectionObjectSub> collection;
};
Sub contains a vector and MyImpl contains a vector iterator. I'd like to instantiate a Base::Iterator with impl_ pointing at a MyImpl. If MyImpl::operator== takes a MyImpl& then it isn't overloading Base::Iterator::Impl::operator==, but if it takes a Base::Iterator::Impl& then I can't access the vector iterator even if it actually is a MyImpl.
It seems like I need to do a dynamic cast to get a MyImpl, which requires RTTI. I've heard to avoid using RTTI if possible. Is there another way?
So, you want to return an iterator by value, but have its dynamic type vary depending on the override of begin/end you called? No problem - just add another layer of indirection.
class Base {
public:
class Iterator {
public:
struct Impl {
virtual ~Impl() {}
virtual CollectionObjectBase& operator*() = 0;
virtual void operator++() = 0;
virtual bool operator==(Iterator::Impl const &other) const = 0;
};
Iterator() {}
explicit Iterator(std::unique_ptr<Impl> &&i) : impl_(std::move(i)) {}
Iterator(Iterator &&other) = default;
CollectionObjectBase& operator*() { return **impl_; }
Iterator& operator++() { ++*impl_; return *this; }
bool operator==(Iterator const &other) const {
return (!impl_ && !other.impl_) || (*impl_ == *other.impl_);
}
private:
std::unique_ptr<Impl> impl_;
};
// ...
This uses the pointer-to-impl (pimpl) idiom to give each concrete subclass of Base its own concrete subclass of Base::Iterator::Impl, but still let you pass Base::Iterator objects around by value using move semantics to transfer ownership of the dynamic object.
NB. I made two default-constructed (nullptr) iterators compare equal so you don't need to create a real instance for end.
I have created an interface class which defines a Queue for Childpointers.
class IChildQueue
{
public:
IChildQueue(void) {};
virtual ~IChildQueue(void) {};
public:
virtual bool add(ChildProcess *oChildProcess) = 0;
virtual void remove(ChildProcess *oChildProcess) = 0;
virtual void clear(void) = 0;
virtual unsigned int size(void) = 0;
virtual const IChildQueueIterator &begin(void) = 0; <-- this is the problem
};
Now I wanted to add an iterator to the interface so that a client can iterate over the childs without messing with the queue itself.. As my knowledge of C++ is not THAT good, I didn't manage to get this working.
My goal was what I can use the iterator conveniently in a for loop, so it should have autostorage duration and it should act as a proxy to the underlying object. i.E. like this:
for(Iterator it = master.begin(); it != it.end(); ++it)
it->childfunction(); <-- by overloading the -> operator.
And No, I don't want to use boost for various reasons.
So far my Iterator looks like this:
class IChildQueueIterator
{
public:
IChildQueueIterator(IChildQueue *pQueue);
virtual ~IChildQueueIterator() {};
virtual ChildProcess *operator->() const = 0;
virtual bool operator==(IChildQueueIterator const &lhs) = 0;
virtual bool operator!=(IChildQueueIterator const &lhs) = 0;
virtual ChildProcess &operator++() = 0;
virtual const ChildProcess operator++(int) = 0;
virtual bool end(void) = 0;
};
I'm not sure if this even possible, but I would at least like to know why, if this is indeed the case.
I am porting this code from Visual C++ 6.0 (it also worked with an older GCC++) to Visual Studio 2010 C++. The code compiles but throws an exception.
I have an base class, CncMatchedQueryAtom. This class is used contain matches of different types of target atoms (this is a graph matching application) for 99% of the cases there is a one to one match between the query and the target. This is handled by the derived class, CncMatchedQueryAtomSimple. This class works great. The problem is that some query atoms match groups of atoms, this is handled by the class, CncMatchedQueryAtomGroup. This class contains a vector with the matched atoms. I want the iterator class defined within the base class to encapsulate the vector iterator in the derived class such that begin() returns the vector begin() and the end returns the vector's end().
The old version has problems on the end() at runtime because it does the conversion by:
return &*group.end();
Which is no longer allowed by Visual C++
So how can a base class specify an iterator that derived classes can implement? This doesn't seem very obvious to me, but I'm new to C++. Nor is it something that seasoned C++ developers that I work with know of either.
Basically, I want the base class to have methods that provide begin and end functions that the derived classes implement.
Here is the code:
class CncMatchedQueryAtom
{
protected:
int notBlockAllocated;
public:
int allocateIndividually() const
{
return notBlockAllocated;
}
const CncAtom *queryAtom;
CncAtom *queryAtomVolitile() const
{
return (CncAtom*)queryAtom;
}
// set when the class has been allocated by newing
// intialize all default constructors to be notBlockAllocated
CncMatchedQueryAtom()
: notBlockAllocated(1)
, queryAtom(NULL) // i don't think this needs to be initialized to null
{
}
CncMatchedQueryAtom(int noBlock)
: notBlockAllocated(noBlock)
, queryAtom(NULL) // i don't think this needs to be initialized to null
{
}
// may not need this now that it's a virtual!
CncMatchedQueryAtom(const CncMatchedQueryAtom &that)
: queryAtom(NULL)
{
*this = that;
}
// this needs to be virtual so when delete CncMatchedQueryAtom is called
// the virtual calss members are destructed too
virtual ~CncMatchedQueryAtom()
{
}
virtual void dump() const =0;
virtual void clearMapping() =0;
virtual CncMatchedQueryAtom *newCopy() const =0;
virtual void coverHits(class CncTarget *) const = 0;
// iterates over all matched target atoms for this query atom
class iterator
{
private:
CncMatchedTargetAtom *ptr;
public:
iterator()
{
}
iterator(const CncMatchedTargetAtom *targetAtom) // constructor from a target ptr
:ptr((CncMatchedTargetAtom *)targetAtom)
{
}
iterator(const iterator &oldOne)
:ptr(oldOne.ptr)
{
}
~iterator()
{
}
int operator==(const iterator &that) const
{
return ptr==that.ptr;
}
int operator!=(const iterator &that) const
{
return ptr!=that.ptr;
}
const CncMatchedTargetAtom &operator*() const
{
return *ptr;
}
iterator operator++(int NotUsed) // post increment
{
iterator returnValue(*this);
++ptr;
return returnValue;
}
iterator &operator++() // pre increment
{
++ptr;
return *this;
}
int operator<(const iterator &rhs) const
{
return (this->ptr < rhs.ptr);
}
CncMatchedTargetAtom *operator->()
{
return ptr;
}
};
virtual iterator begin() const =0;
virtual iterator end() const =0;
virtual int size() const = 0;
virtual double molecularWeight() const = 0;
const CncAtom *getFirstTargetAtom() const
{
return (*begin()).matchedTargetAtom;
}
CncAtom *getFirstTargetAtomVolitile() const
{
return (CncAtom*)getFirstTargetAtom();
}
}; // class CncMatchedQueryAtom
class CncMatchedQueryAtomSimple : public CncMatchedQueryAtom
{
public:
// we need a constructor here since this is allocated with blockAlloc
CncMatchedQueryAtomSimple()
: CncMatchedQueryAtom(0)
{
}
// we use simple.targetAtom as a temporary variable
// used to pass to matching functions
CncMatchedTargetAtom simple;
void clearIt()
{
queryAtom=NULL;
notBlockAllocated=0;
}
// if queryAtom is an element-type atom (or Lp or A atom)
void dump() const;
void clearMapping()
{
}
CncMatchedQueryAtom *newCopy() const
{
// since this is usually not allocatedIndividually I'll set
// the notBlockAllocatedFlag on the copy to be sure if this
// does happen it will individually deallocate it
CncMatchedQueryAtomSimple *retVal = new CncMatchedQueryAtomSimple(*this);
retVal->notBlockAllocated = 1;
return (CncMatchedQueryAtom *)retVal;
}
void coverHits(class CncTarget *) const;
iterator begin() const
{
return &simple;
}
iterator end() const
{
return &simple+1;
}
int size() const
{
return 1;
}
double molecularWeight() const
{
return CncMolGetAtomicMassAve(simple.matchedTargetAtom->getAtomicNumber());
}
}; // class CncMatchedQueryAtomSimple
class CncMatchedQueryAtomGroup : public CncMatchedQueryAtom
{
public:
// if queryAtom is an R- or X-group searching for
std::vector<CncMatchedTargetAtom> group;
void dump() const;
void clearMapping()
{
group.clear();
}
CncMatchedQueryAtom *newCopy() const
{
return new CncMatchedQueryAtomGroup(*this);
}
void coverHits(class CncTarget *) const;
iterator begin() const
{
return &*group.begin();
}
iterator end() const
{
// this is a hack, works with Visual C++ 6.0 and older GCC++ but not VS C++ 2010
return &*group.end(); // Throws error at runtime! Iterator Not Dereferencable
}
int size() const
{
return group.size();
}
double molecularWeight() const
{
double sum=0;
std::vector<CncMatchedTargetAtom>::const_iterator q;
for (q=group.begin()
; q!=group.end()
; ++q)
{
sum += CncMolGetAtomicMassAve(q->matchedTargetAtom->getAtomicNumber());
}
return sum;
}
}; // class CncMatchedQueryAtom
An example of how the iterator is called:
// Sample call to the iterator
// (*elem)->getMatchedAtom() returns a CncMatchedQueryAtom *
CncMatchedQueryAtom::iterator atomMatched;
// welp it looks like we have to do these
//(*elem)->getFirstTargetAtom
for (atomMatched=(*elem)->getMatchedAtom()->begin()
; atomMatched!=(*elem)->getMatchedAtom()->end() // Runtime exception here!
; ++atomMatched)
{
existenceFingerprint.setBit(
atomMatched->matchedTargetAtom->indexInStructure);
}
Thanks, hopefully this isn't too much code...
You cannot convert iterators from one container into iterators to another container.
It used to work with VC6, because they happened to use a pointer as vector::iterator. Later versions have an iterator class where the conversion does not work.