更新
我在一个我无法使用STL的环境中处理一些容器代码。我试图概括我的迭代器,以减少代码重复。我遇到过一种情况,我有一个容器,可以包含对象或指向对象的指针。在尝试编译以下(人为的)代码时,我遇到了编译问题:
struct Object
{
};
template<typename Container, typename T>
struct IteratorBase
{
IteratorBase( Container * container, T curr ) : _container( container ), _curr( curr ) { }
Container * _container;
T _curr;
T & GetValue() const { return _curr; }
void Invalidate() { _curr = NULL; }
};
template<typename T>
struct Container
{
typedef typename T * Type;
typedef IteratorBase<Container<T>, Type> Iterator;
Iterator GetIterator() { return Iterator( this, storage ); }
T storage[10];
};
int main(int argc, char* argv[])
{
Container<Object> containerByAddress;
const Object* pA = containerByAddress.GetIterator().GetValue();
return 0;
}
错误是
error C2440: 'return' : cannot convert from 'Object *const ' to 'Object *&'
while compiling class template member function 'Object &IteratorBase<Container,T>::GetValue(void) const'
所以我做了一些更改,通过使用以下方法推断T的类型来改变返回值的方式:
template<typename T>
struct DetermineReturnType
{
typedef T & ReturnType;
};
template<typename T>
struct DetermineReturnType<T*>
{
typedef T * ReturnType;
};
template<typename Container, typename T>
struct IteratorBase
{
IteratorBase( Container * container, T curr ) : _container( container ), _curr( curr ) { }
Container * _container;
T _curr;
typedef typename DetermineReturnType<T>::ReturnType ReturnType;
ReturnType GetValue() const { return _curr; }
void Invalidate() { _curr = NULL; }
};
现在我的迭代器使用&amp;或*基于T。
但我的问题是 - 这是一个合理的解决方案吗?我有什么办法可以解决这个问题吗?
请注意我不能使用STL,Boost或最新版本的C ++,因为这是一个嵌入式系统已有几年了。
感谢您的任何见解。
答案 0 :(得分:2)
问题在于GetValue()
被声明为const
,但您正在返回对成员变量的非const
引用。如果编译器允许您这样做,您将能够在迭代器的可能const
限定实例中修改成员变量。您可以通过同时提供const
和非const
版GetValue()
来轻松解决此问题。编译器将根据迭代器实例的CV限定符选择适当的版本。
T const& GetValue() const { return _curr; }
T& GetValue() { return _curr; }
不幸的是,这不太可能让你获得正在寻找的真实行为。你真的不应该在这里返回一个引用,因为它只允许你更改迭代器内的元素而不是容器中的元素。要获得您想要的位置,您需要更改的不仅仅是GetValue
实现,还需要重新设计迭代器以使用容器中的元素,而不是在本地维护它。
以下是您如何处理此问题的基本示例。它返回对容器中元素的引用,允许您通过迭代器修改容器。由于我没有完整版本的Container
我使用裸阵列,但可见的最终结果应该很容易掌握。
#include <iostream>
struct Object { };
template<typename T>
struct IteratorBase
{
IteratorBase(T* initialPtr) : _curr(initialPtr) {}
T* _curr;
T const & GetValue() const { return *_curr; }
T& GetValue() { return *_curr; }
void next() { ++_curr; }
void prev() { --_curr; }
};
int main()
{
Object a, b, c, d, e;
Object *objects[] = { &a, &b, &c, &d, &e };
IteratorBase<Object*> it(objects);
for (int i = 0; i < sizeof(objects) / sizeof(*objects); i++)
{
std::cout << it.GetValue() << "\n";
it.GetValue() = NULL;
it.next();
}
it = IteratorBase<Object*>(objects);
for (int i = 0; i < sizeof(objects) / sizeof(*objects); i++)
{
std::cout << it.GetValue() << "\n";
it.next();
}
}