Question

J'utilise C # depuis un moment maintenant, et revenir en C ++ est un casse-tête. J'essaie de transférer certaines de mes pratiques de C # en C ++, mais je rencontre une certaine résistance et je serais heureux d'accepter votre aide.

Je voudrais exposer un itérateur pour une classe comme celle-ci:

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

Est-ce que j'essaie quelque chose qui ne pose pas de problème? Devrais-je simplement taper std :: vector & Lt; T & Gt; :: iterator? J'espère juste en fonction de l'itérateur, pas du conteneur de mise en œuvre ...

Était-ce utile?

La solution

Vous pouvez trouver l'article suivant intéressant car il résout exactement le problème que vous avez posté: Sur la tension Entre la programmation orientée objet et la programmation générique en C ++ et ce que l’effacement de type peut faire à ce sujet

Autres conseils

J'ai déjà effectué les opérations suivantes pour obtenir un itérateur indépendant du conteneur. C’est peut-être exagéré, car j’aurais aussi pu utiliser une API dans laquelle l’appelant passe un vector<T*>& qui doit être rempli avec tous les éléments, puis l’appelant peut simplement effectuer une itération directement à partir du vecteur.

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

Cela devrait faire ce que vous voulez:

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

De C ++ accéléré :

  

Chaque fois que vous avez un type, tel que vector<T>, qui dépend d'un paramètre de modèle et que vous souhaitez utiliser un membre de ce type, tel que size_type, qui est lui-même un type, vous devez faire précéder l'intégralité du type. nom par typename pour permettre à la mise en oeuvre de traiter le nom en tant que type.

Je ne suis pas sûr de ce que vous entendez par & "ne pas exposer std :: vector publiquement &"; mais en effet, vous pouvez simplement définir votre typedef comme ceci:

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

Vous pourrez modifier ces types de texte plus tard sans que l'utilisateur ne remarque quoi que ce soit ...

Soit dit en passant, il est recommandé d’exposer également quelques autres types si vous souhaitez que votre classe se comporte comme un conteneur:

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;

Et si votre classe en a besoin:

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

Vous trouverez la signification de toutes ces typedef ici: documentation STL sur les vecteurs

Modifier: ajout du typename comme suggéré dans les commentaires

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top