将返回值定义为*或&amp;基于自定义迭代器<t> </t>

时间:2014-11-28 23:10:28

标签: c++ templates reference iterator return-type

更新

我在一个我无法使用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 ++,因为这是一个嵌入式系统已有几年了。

感谢您的任何见解。

1 个答案:

答案 0 :(得分:2)

问题在于GetValue()被声明为const,但您正在返回对成员变量的非const引用。如果编译器允许您这样做,您将能够在迭代器的可能const限定实例中修改成员变量。您可以通过同时提供const和非constGetValue()来轻松解决此问题。编译器将根据迭代器实例的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();
    }
}