2008-10-01 12 views
22

C# 'yi bir süredir kullanıyorum ve C++' ya geri dönmek baş ağrıyor. C# 'den bazı uygulamalarımı C++' ya taşımaya çalışıyorum ama biraz direnç buluyorum ve yardımınızı kabul etmekten memnuniyet duyarım.Kullanılan kapsayıcıyı açığa çıkarmadan yineleyicileri nasıl gösterebilirim?

Böyle bir sınıf için bir yineleyici maruz istiyorum:

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

Ben bir sorun değildir şeye çalışıyor muyum? Sadece std yazmalıyım :: vector < T> :: yineleyici? Ben

+0

Ayrıca http://stackoverflow.com/questions/127009/returning-an-any-kind-of-input-iterator-instead-of-a-vectoriterator-or-a (bu [soruyu] bakınız -listit) –

cevap

2

İstediğin yapmalıyım ... sadece yineleyici değil, uygulayıcı konteyner bağlı üzerine umuyorum:

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

Accelerated C++ Gönderen:

Bir tipin yaşadığımızda

, vector<T> gibi, bir şablon parametresine bağlıdır ve bu türden bir üyeyi kullanmak istediğiniz, örneğin, bir tür olan size_type gibi, uygulamanın adını ad olarak kabul etmesini sağlamak için tüm adı önce typename olmalıdır. bir tür.

1

sana "alenen std :: vector maruz bırakmakla" ile ne demek emin değilim ama aslında, sadece o sevdiği typedef tanımlayabilirsiniz:

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

Bu typedefs değiştirmek mümkün olacak

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; 
: daha sonra arada kullanıcı bir şey fark ...

olmadan, size sınıf kapsayıcı olarak davranmasını istiyorsanız Ayrıca birkaç diğer türleri ortaya çıkarmak için uygulama iyi sayılır

Ve sınıfı tarafından gerekirse: STL documentation on vectors

Düzenleme::

Burada var typedef tüm bu anlamını bulacaksınız Yorum önerilen olarak typename eklendi

+0

Belki biraz fazla abartıyorum, ama ben sadece gerçek kapsayıcı değil, stl yineleyicileri kullanıyorum göstermek için yazım hatası istiyorum. Std :: vector :: yineleyici yineleyici yazılırsa, insanlar sadece std :: vektör <ínt> :: iterator iter = example.Begin(); (devam) – Statement

+0

Bu ilk başta bir problem gibi görünmese de, sınıfımın içsel uygulamasının yerine bir liste kullanmasını değiştirdiğimi düşünün.Müşteri kodu kırılırdı. Birçok farklı kapsayıcıyla çalışan ortak bir yineleyici kullanmak bu sorunu çözecektir. Sorun şu ki, bunu yapmanın bir yolunu bulamadım. – Statement

+0

Gönderiniz için küçük düzeltme: T bir şablon parametresi olduğu için, typedame anahtar sözcüğünü yazım dosyalarınızda kullanmalısınız, yani typedef typename std :: vector :: yineleyici yineleyici; –

2

Aşağıdakileri daha önce yaptım hat kapsayıcıdan bağımsız bir yineleyici aldım. Bu, arayanın tüm elemanlarla doldurulması gereken bir vector<T*>& numaralı telefondan geçtiği ve daha sonra arayanın doğrudan vektörden yineleyebileceği bir API kullanabildiğim için bu fazla olabilirdi.

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

Tamam, ancak standart bir yineleyici değil. Direksiyonu yeniden icat etmemeyi tercih ederim. Diğerlerinin zaten standart yineleyicilerde kullanılması bekleniyor, orada öğrenme eğrisi yok. –