Подтвердить что ты не робот

Как я могу выставить итераторы, не подвергая контейнер использованию?

Я использую С# в течение некоторого времени, а возврат к С++ - головная боль. Я пытаюсь получить некоторые из своих практик от С# со мной до С++, но я нахожу некоторое сопротивление, и я был бы рад принять вашу помощь.

Я хотел бы открыть итератор для класса следующим образом:

template <class T>
class MyContainer
{
public:
    // Here is the problem:
    // typedef for MyIterator without exposing std::vector publicly?

    MyIterator Begin() { return mHiddenContainerImpl.begin(); }
    MyIterator End() { return mHiddenContainerImpl.end(); }

private:
    std::vector<T> mHiddenContainerImpl;
};

Я пытаюсь что-то, что не проблема? Должен ли я просто typedef std::vector <T> :: итератор? Я надеюсь, что это зависит только от итератора, а не от контейнера-реализации...

4b9b3361

Ответ 2

Это должно делать то, что вы хотите:

typedef typename std::vector<T>::iterator MyIterator;

От Ускоренный С++:

Всякий раз, когда у вас есть тип, например vector<T>, который зависит от параметра шаблона, и вы хотите использовать член этого типа, например size_type, который сам по себе является типом, вы должны предшествовать всему name typename, чтобы реализовать реализацию, чтобы обработать имя как тип.

Ответ 3

Ранее я сделал следующее, чтобы получить итератор, не зависящий от контейнера. Возможно, это было излишним, поскольку я мог также использовать API, в котором вызывающий абонент переходит в vector<T*>&, который должен быть заполнен всеми элементами, а затем вызывающий может просто перебирать из вектора напрямую.

template <class T>
class IterImpl
{
public:
    virtual T* next() = 0;
};

template <class T>
class Iter
{
public:
    Iter( IterImpl<T>* pImpl ):mpImpl(pImpl) {};
    Iter( Iter<T>& rIter ):mpImpl(pImpl) 
    {
        rIter.mpImpl = 0; // take ownership
    }
    ~Iter() {
        delete mpImpl; // does nothing if it is 0
    }
    T* next() {
    return mpImpl->next(); 
    }
private:
    IterImpl<T>* mpImpl; 
};

template <class C, class T>
class IterImplStl : public IterImpl<T>
{
public:
    IterImplStl( C& rC )
    :mrC( rC ),
    curr( rC.begin() )
    {}
    virtual T* next()
    {
    if ( curr == mrC.end() ) return 0;
    typename T* pResult = &*curr;
    ++curr;
    return pResult;
    }
private:
    C& mrC;
    typename C::iterator curr;
};


class Widget;

// in the base clase we do not need to include widget
class TestBase
{
public:
    virtual Iter<Widget> getIter() = 0;
};


#include <vector>

class Widget
{
public:
    int px;
    int py;
};

class Test : public TestBase
{
public:
    typedef std::vector<Widget> WidgetVec;

    virtual Iter<Widget> getIter() {
        return Iter<Widget>( new IterImplStl<WidgetVec, Widget>( mVec ) ); 
        }

    void add( int px, int py )
    {
        mVec.push_back( Widget() );
        mVec.back().px = px;
        mVec.back().py = py;
    }
private:
    WidgetVec mVec;
};


void testFn()
{
    Test t;
    t.add( 3, 4 );
    t.add( 2, 5 );

    TestBase* tB = &t;
    Iter<Widget> iter = tB->getIter();
    Widget* pW;
    while ( pW = iter.next() )
    {
        std::cout << "px: " << pW->px << " py: " << pW->py << std::endl;
    }
}

Ответ 4

Я не уверен, что вы подразумеваете под "не разоблачением std::vector публично", но действительно, вы можете просто определить свой typedef следующим образом:

typedef typename std::vector<T>::iterator iterator;
typedef typename std::vector<T>::const_iterator const_iterator; // To work with constant references

Вы сможете изменить эти typedefs позже, если пользователь ничего не заметит...

Кстати, считается хорошей практикой также выставлять несколько других типов, если вы хотите, чтобы ваш класс вел себя как контейнер:

typedef typename std::vector<T>::size_type size_type;
typedef typename std::vector<T>::difference_type difference_type;
typedef typename std::vector<T>::pointer pointer;
typedef typename std::vector<T>::reference reference;

И если вам нужен ваш класс:

 typedef typename std::vector<T>::const_pointer const_pointer;
 typedef typename std::vector<T>::const_reference const_reference;

Здесь вы найдете смысл всех этих typedef: Документация STL на векторы

Изменить: добавлен typename, как предложено в комментариях