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 Barobject
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