簡體   English   中英

在stl容器包裝器中定義迭代器類型

[英]Define an iterator type in a stl container wrapper

在STL容器周圍編寫包裝類的正確方法是什么,它也是一個模板(可以接受泛型類型T作為元素)並允許我像直接使用STL容器一樣使用迭代器?

我想做以下類型的事情

#include <list>
#include <iostream>

class MyClass{};

template<class T>
class Wrapper
{
    public:
        typename std::list<T>::iterator iterator;

        std::list<T> elements;
        iterator begin(){ return elements.begin(); };
        iterator end(){ return elements.end(); };
};

int main()
{
    Wrapper<MyClass> wrapper;

    for (Wrapper::iterator it = wrapper.begin(); it != wrapper.end(); ++it)
        std::cout<<"Hi"<<std::endl;
}

但是編譯器說:

 error: ‘iterator’ in ‘class Wrapper<T>’ does not name a type

你有兩個錯誤。

就像Igor Tandetnik在評論中所說,你的iterator是一個數據成員,而不是你的案例的嵌套類型。

你必須在班上這樣做:

typedef typename std::list<T>::iterator iterator;

或者,在C ++ 11中:

using iterator = typename std::list<T>::iterator;

此外,您在main()代碼中使用錯誤的方式使用iterator 它應該是這樣的:

Wrapper<MyClass>::iterator it = wrapper.begin()

或者,在C ++ 11或更高版本中,您可以這樣做:

for(const auto &element : wrapper) {
    ...
}

就個人而言,我更喜歡使用私有繼承而不是封裝。 在我的腦海中,公共繼承意味着“IS A”關系,而私人繼承意味着“實施中的關系”。

你可以這樣做:

template<typename T>
class WrapperList : private List<T> {
    ... Your code that belongs to your wrapper
}

如果你想包裝std :: list並通過一些功能來豐富它,實際上,在包裝器中維護一些(或大多數)std :: list接口(作為迭代功能),還有(至少)兩個可能性。

一個(組合)是在包裝器中定義begin(),end()方法和迭代器類型,以便將它們傳播到包含的結構,如Andrea Araldo所提出的。

一個(私有繼承)是利用私有繼承,在某些情況下這可能非常方便。 需要的步驟:

  • 私有地從std :: list派生
  • 實現特定於包裝器的方法,如果有的話(你需要在包裝器中添加什么)
  • 通過'using-declaration'( http://en.cppreference.com/w/cpp/language/using_declaration )在包裝器接口中公開你感興趣的std :: list公共接口的方法和類型。 。

例如,在下文中,在這個意義上(WrapperPrivInh)對所提出的片段進行了略微修改。 在這種情況下,std :: list的所有標准構造函數都可以在包裝器接口中免費獲得。 此外,為了完整性,還提出了WrapperCompos變體,其中列表包含在包裝器中,它公開了支持基於迭代器的循環所需的內容。 在這種情況下,只從頭開始重新定義“默認元素數量”構造函數。

#include <list>
#include <iostream>

class MyClass
{ 
public:
    MyClass() { std::cout<<"(DEBUG)MyClass::default constructor\n"; }
};

template<class T>
class WrapperPrivInh : private std::list<T>
{
    public:
        using std::list<T>::iterator;  //for the iterator type
        using std::list<T>::begin;     // for the begin()
        using std::list<T>::end;       //  and end() methods
        using std::list<T>::list;      // for the constructors, if needed

        //std::list<T> elements;
        //iterator begin(){ return elements.begin(); };
        //iterator end(){ return elements.end(); };
};

template<class T>
class WrapperCompos 
{
    std::list<T> m_list;

    public:
        using iterator= typename std::list<T>::iterator;  //for the iterator type

        WrapperCompos(int const n) : m_list(n) { }

        iterator begin(){ return m_list.begin(); };
        iterator end(){ return m_list.end(); };
};


int main()
{
    {
        std::cout<<"Experiment with private inheritance"<<'\n';
        WrapperPrivInh<MyClass> wrapper(3);  // constructor witch builds N (3 here) MyClass default elements (derived "for free" from std::list)

        for(WrapperPrivInh<MyClass>::iterator it = wrapper.begin(); it != wrapper.end(); ++it)
            std::cout<<"Hi "<<&(*it)<<std::endl;
    }

    {
        std::cout<<"\nExperiment with private inheritance"<<'\n';
        WrapperCompos<MyClass> wrapper(3);  // constructor witch builds N (3 here) MyClass default elements (derived "for free" from std::list)

        for(WrapperCompos<MyClass>::iterator it = wrapper.begin(); it != wrapper.end(); ++it)
            std::cout<<"Hi "<<&(*it)<<std::endl;
        for( auto const& x : wrapper )  //range-for-loop syntax (from c++11)
            std::cout<<"Hi2 "<<&x<<std::endl;
    }
}

私有繼承方法可以很容易地,並且正確地將包裝結構的特征傳播到包裝器。 例如,如果包裝結構與它們兼容,則包裝器可以很容易地與std :: algorithms兼容,就像std :: list一樣。 希望這可以幫助。 最好

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM