Using different iterator types in subclasses without breaking theinheritance mechanism

A

Alfredo Di Napoli

Hi everyone!

Lately I am facing a problem with templates and iterators, but first
let me describe what I'm trying to do, so that my question is clearer.

I have one common class, MemoryObj<T>, and every memory management
class derive from it.

Now, I need to define two different classes: a "buffer" and a
"fundamental type". The first one, Buffer<T>, is a list of
MemoryChunk<T> stored as a std::vector< MemoryChunk<T>* >, while
Fundamental<T> is a wrapper to fundamental types (e.g., int, long,
double, ...), and for compatibility, it inherits from MemoryObj<T>, as
I already said.

The hard part: I want to implement iterator support for these classes.
So, I tried to add a simple iterator facility in my classes:



template<typename T, class Iterator = typename
std::vector<T>::iterator>
class MemoryObj
{
public:
typedef Iterator iterator;
virtual Iterator begin() = 0;
virtual Iterator end() = 0;
private:
};


Then, my memory chunk class will simply use std::vector<T>::iterator
to access its elements:



template <typename T, class Iterator = typename
std::vector<T>::iterator>
class MemoryChunk: public MemoryObj<T, Iterator>
{
public:
MemoryChunk(const std::vector<T>& vector): b_(vector) { }

size_t const size() const { return b_.size(); }
T& operator[](size_t i){ return b_; }
const T& operator[](size_t i) const{ return b_; }

typedef Iterator iterator;

iterator begin() { return b_.begin(); }
iterator end() { return b_.end(); }
private:
std::vector<T> b_;
};


And finally, my custom iterator for Buffer<T>:



template <typename T>
class BufferIterator: public std::vector<T>::iterator
{
public:
BufferIterator() { /* Code */ }
BufferIterator operator=( const BufferIterator& rhs ) { /* Code
*/ }

BufferIterator static begin(std::vector<MemoryChunk<T>*>& v) { /*
Code */ }
BufferIterator static end(std::vector<MemoryChunk<T>*>& v) { /*
Code */ }

T& operator*() { /* Code */ }
BufferIterator operator++(int) { /* Code */ }
BufferIterator& operator++() { /* Code */ }
BufferIterator operator+(const int n) { /* Code */ }
bool operator!=(const BufferIterator& b) const { /* Code */ }
private:
int currentChunk_;
int globalCounter_;
int stepCounter_;
T currentValue_;
std::vector<MemoryChunk<T> *>* vec_;
};

template <typename T, class Iterator = BufferIterator<T> >
class Buffer: public MemoryObj<T,Iterator>
{
public:
Buffer() { }

void push_back(MemoryChunk<T>& c) { chunks_.push_back(&c); }

size_t const size() const
{
size_t s = 0;
for (int i = 0; i < chunks_.size(); i++) {
s += chunks_->size();
}
return s;
}

MemoryChunk<T>& chunks(size_t idx) { return *chunks_[idx]; }

typedef Iterator iterator;

iterator begin(){ return iterator::begin(chunks_); }
iterator end(){ return iterator::end(chunks_); }
private:
std::vector<MemoryChunk<T>*> chunks_;
};



The iterators works fine... until I try to use functions that, as a
generic as I want my code to be, take as argument a MemoryObj<T>&, and
pass to these a Buffer<T>:



template <typename T>
void static genericFunction(MemoryObj<T>& obj)
{
typename MemoryObj<T>::iterator i = obj.begin();
std::cout << "The generic value is: " << *(i) << std::endl;
}

int main()
{
//Data creation
std::vector<int> v1(6,23);
std::vector<int> v2(4,18);
MemoryChunk<int> m1(v1);
MemoryChunk<int> m2(v2);

Buffer<int> b1;
b1.push_back(m1); b1.push_back(m2);

//Attempts with iterators over Buffer<T> work like a charm!
Buffer<int>::iterator it = b1.begin();
std::cout << "Simple access with operator* : ";
for (int i = 0; i < b1.size(); i++) {
int tmp = (*it);
std::cout << tmp << " ";
it++;
}
std::cout << std::endl;

//Invoke a generic function HUGE FAILURE!
std::cout << "Calling the generic function on MemoryChunk : " <<
std::endl;
genericFunction(m1); // This works just fine

std::cout << "Calling the generic function on Buffer : " <<
std::endl;
genericFunction(b1); //---> THIS FAILS

return 0;
}


Compiling the code, I get an error which I can't decrypt:

candidate function [with T = int] not viable: no known conversion
from 'Buffer<int>' to 'MemoryObj<int> &' for 1st argument [3]

I suspect the problem is related to the BufferIterator, cause
MemoryObj and MemoryChunk use a different iterator type (a
std::vector<T>::iterator), so the compiler doesn't know how to perform
the conversion. What am I doing wrong with my classes?

I am puzzled by this, and any help will be deeply appreciated!

You can download the source code on SourceForge at the following URL:

http://sourceforge.net/p/laetus/code/132/tree/branches/buffer-iterators/laetus-iterators/iterators/


Thanks a lot!
Alfredo
 
L

LR

Alfredo said:
Hi everyone!
I have one common class, MemoryObj<T>, and every memory management
class derive from it.

Now, I need to define two different classes: a "buffer" and a
"fundamental type". The first one, Buffer<T>, is a list of
MemoryChunk<T> stored as a std::vector< MemoryChunk<T>* >, while
Fundamental<T> is a wrapper to fundamental types (e.g., int, long,
double, ...), and for compatibility, it inherits from MemoryObj<T>, as
I already said.

The hard part: I want to implement iterator support for these classes.
So, I tried to add a simple iterator facility in my classes:

It's not clear to me how the code you posted solves your problem. I
think it might be easier to take a class and add some typedefs including
iterator and const_iterator and some begin and end methods.

I don't think it will solve your problem, but you may want to chance this
template <typename T, class Iterator = BufferIterator<T> >
class Buffer: public MemoryObj<T,Iterator>

to

template<
typename T,
class Buffer: public InheritFromThisObject

and put this in the class,

typedef BehaveLikeThisIterator iterator;

As I say, I don't think it will solve your problem, but it may point you
in the right direction.


And,
int main()
change,

Buffer<int> b1;

to
Buffer<int, std::vector<int>::iterator> b1;

There will be a couple of other things to change.

I didn't look there. But this may be useful,
http://www.parashift.com/c++-faq-lite/how-to-post.html#faq-5.8

HTH
 
A

Alfredo Di Napoli

It's not clear to me how the code you posted solves your problem.  I
think it might be easier to take a class and add some typedefs including
iterator and const_iterator and some begin and end methods.

I need different iterators because a Buffer is an aggregation of
MemoryChunk, so
iterating over a Buffer means iterating over different MemoryChunk,
each one physically
stored in non contiguous portion of memory. So I need a specific
iterator for the class.

to

template<
    typename T,
    class BehaveLikeThisIterator = BufferIterator<T>,
    class InheritFromThisObject = MemoryObj<T,BehaveLikeThisIterator>

class Buffer: public InheritFromThisObject

and put this in the class,

     typedef BehaveLikeThisIterator iterator;

As I say, I don't think it will solve your problem, but it may point you
in the right direction.

I can't figure out how your tips can solve problem, it seems to make
it even more complex, though.
And,


to
      Buffer<int, std::vector<int>::iterator> b1;

There will be a couple of other things to change.

I can't change this, the Buffer iterator type must be a
BufferIterator, it's a constraint of my domain.

Sorry if I haven't adhered to the netiquette, but it's my first post
on this group, and I thought that
a properly highlighted code posted as a separate URL would have been
better than a plain text email :)

Thanks anyway,
A.
 
L

LR

I can't change this, the Buffer iterator type must be a
BufferIterator, it's a constraint of my domain.

Then maybe you can change genericFunction to something like:


template <typename T, typename Iterator>
void static someOtherGenericFunction(MemoryObj<T,Iterator> &obj)
{}

I think your problem is that Buffer inherits from
MemoryObj<T,Iterator> but the Buffer's default Iterator template
argument is not the same as MemoryObj<T>'s default Iterator template
argument.

IOW
MemoryChunk<int> inherits from MemoryObj<int>
MemoryObj<int> is MemoryObj<int,std::vector<int>::iterator>>
but
Buffer<int> inherits from MemoryObj<int,BufferIterator<int>>
 
A

Alfredo Di Napoli

template <typename T, typename Iterator>
void static someOtherGenericFunction(MemoryObj<T,Iterator> &obj)
{}

Thank you. The solution was so easy that I wonder how I couldn't think
about it before.
Regards,
Alfredo
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,962
Messages
2,570,134
Members
46,690
Latest member
MacGyver

Latest Threads

Top