Pregunta

He estado usando C # por un tiempo y volver a C ++ es un dolor de cabeza. Estoy tratando de llevar algunas de mis prácticas de C # conmigo a C ++, pero estoy encontrando cierta resistencia y me complacería aceptar su ayuda.

Me gustaría exponer un iterador para una clase como esta:

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;
};

¿Estoy intentando algo que no es un problema? ¿Debo escribir typedef std :: vector & Lt; T & Gt; :: iterador? Espero solo dependiendo del iterador, no del contenedor de implementación ...

¿Fue útil?

Solución

Puede encontrar interesante el siguiente artículo, ya que aborda exactamente el problema que ha publicado: Sobre la tensión Entre la programación orientada a objetos y genérica en C ++ y qué tipo de borrado puede hacer al respecto

Otros consejos

He hecho lo siguiente antes para obtener un iterador que era independiente del contenedor. Esto puede haber sido excesivo ya que también podría haber usado una API donde la persona que llama pasa en un vector<T*>& que debe rellenarse con todos los elementos y luego la persona que llama puede iterar directamente desde el vector.

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;
    }
}

Esto debería hacer lo que quieras:

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

De C ++ acelerado :

  

Siempre que tenga un tipo, como vector<T>, que dependa de un parámetro de plantilla, y desee utilizar un miembro de ese tipo, como size_type, que es en sí mismo un tipo, debe preceder a todo nombre por typename para que la implementación sepa que trata el nombre como un tipo.

No estoy seguro de lo que quieres decir con & "; no expongo públicamente std :: vector &"; pero de hecho, puedes definir tu typedef así:

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

Podrá cambiar estos typedefs más tarde sin que el usuario note nada ...

Por cierto, se considera una buena práctica exponer también algunos otros tipos si desea que su clase se comporte como un contenedor:

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;

Y si su clase lo necesita:

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

Encontrará el significado de todos estos typedef aquí: Documentación STL en vectores

Editar: se agregó el typename como se sugiere en los comentarios

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top