I tried to simplify the situation as good as possible.
Basically I have a class that represents a dynamic Array
(here shown as class Array
with size 4) and secondly a class which is a HashMap, and has an Array of Arrays
as a member (here represented by class Bar
).
Both classes implement begin()
and end()
so you can use a foreach loop to iterate over all elements.
The iterator type of Array
is simply T*
and const T*
for the const variant. For Bar
there is a special class Iterator
, which correctly iterates through all members of the Array<Array<T>>
. You should now have a look at the classes I provided, so you know what exactly I'm talking about.
But now there is a problem when I call
bar.begin()
on aconst Bar
object
The Iterator class determines the ArrayIterator
and ElementIterator
types automatically (via decltype of T::begin()), because in my real application almost everything is templated and that's why I don't know the exact type in advance.
I figured out the problem is that decltype(((T*)nullptr)->begin())
always chooses the non-const begin() function of T, which absolutely makes sense since I haven't written (const T*)nullptr
.
If I now call it from a const context, it will fail to assign a const T*
like data.last().end()
to the internal T*
from the decltype which actually should be a const T*
.
I can workaround the problem by declaring a second class ConstIterator
which does everything exactly like the non-const one, but uses (const Array<T>*)nullptr
and (const T*)nullptr
inside the decltype statements.
So what can I do without copying the whole Bar::Iterator class?
Simplified code:
template<class T>
class Array
{
T data[4];
T last() { return data[3]; }
T* begin() { return data; };
T* end() { return data + 4; };
const T* begin() const { return data; };
const T* end() const { return data + 4; };
}
template<class T>
class Bar
{
class Iterator
{
using ArrayIterator = decltype(((Array<T>*)nullptr)->begin());
using ElementIterator = decltype(((T*)nullptr)->begin());
Iterator(const ArrayIterator& beg, const ArrayIterator& end)
{
//initialize the iterator to the first element of the first array
//(and rembember end)
};
Iterator(const ElementIterator& cur)
{
//initialize the iterator to the current element
};
//++ will iterate go to next element and eventually jump to the next array.
//== returns true if the current element is the same
};
Array<T> data;
Iterator begin() { return Iterator(data.begin(), data.end()); };
Iterator end() { return Iterator(data.last().end()); };
Iterator begin() const { return Iterator(data.begin(), data.end()); };
Iterator end() const { return Iterator(data.last().end()); };
};
Aucun commentaire:
Enregistrer un commentaire