简体   繁体   English

在stl容器包装器中定义迭代器类型

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

What it the right way to write a wrapper class around an STL container, which is also a template (can accept a generic type T as element) and allows me to use an iterator as I would do with the STL container directly? 在STL容器周围编写包装类的正确方法是什么,它也是一个模板(可以接受泛型类型T作为元素)并允许我像直接使用STL容器一样使用迭代器?

I want to do something of the following type 我想做以下类型的事情

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

But the compiler says: 但是编译器说:

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

You have two errors. 你有两个错误。

Like Igor Tandetnik said in a comment, your iterator is a data member, not a nested type of your case. 就像Igor Tandetnik在评论中所说,你的iterator是一个数据成员,而不是你的案例的嵌套类型。

You have to do this in your class: 你必须在班上这样做:

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

or, in C++11: 或者,在C ++ 11中:

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

Also, you are using iterator the wrong way in your main() code. 此外,您在main()代码中使用错误的方式使用iterator It should be like this: 它应该是这样的:

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

Or, in C++ 11 or later, you can do this: 或者,在C ++ 11或更高版本中,您可以这样做:

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

Personally, I would prefer to use private inheritance instead of encapsulation. 就个人而言,我更喜欢使用私有继承而不是封装。 In my head, public inheritance means an "IS A" relationship, whereas private inheritance means an "IS IMPLEMENTED IN TERM OF" relationship. 在我的脑海中,公共继承意味着“IS A”关系,而私人继承意味着“实施中的关系”。

You could do it like this: 你可以这样做:

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

If you want to wrap std::list and enrich it by some functionalities and, essentially, maintain some (or most) of the std::list interface (as the iteration capabilities) also in the wrapper, there are (at least) two possibilities. 如果你想包装std :: list并通过一些功能来丰富它,实际上,在包装器中维护一些(或大多数)std :: list接口(作为迭代功能),还有(至少)两个可能性。

One (composition) is to define begin(), end() methods and iterator type in the wrapper as to propagate them to the contained structure, as proposed by Andrea Araldo. 一个(组合)是在包装器中定义begin(),end()方法和迭代器类型,以便将它们传播到包含的结构,如Andrea Araldo所提出的。

One (private inheritance) is to leverage private inheritance, which can be quite handy in some cases. 一个(私有继承)是利用私有继承,在某些情况下这可能非常方便。 Steps needed: 需要的步骤:

  • privately derive from std::list 私有地从std :: list派生
  • implement the wrapper-specific methods, if any (what you need to add in the wrapper) 实现特定于包装器的方法,如果有的话(你需要在包装器中添加什么)
  • expose in the wrapper interface the methods and types of the std::list public interface, which you are interested in, through the 'using-declaration' ( http://en.cppreference.com/w/cpp/language/using_declaration ). 通过'using-declaration'( http://en.cppreference.com/w/cpp/language/using_declaration )在包装器接口中公开你感兴趣的std :: list公共接口的方法和类型。 。

For example, in the following there is a slight modification of the proposed snippet in this sense (WrapperPrivInh). 例如,在下文中,在这个意义上(WrapperPrivInh)对所提出的片段进行了略微修改。 In this case, also all the standard constructors of std::list are made available in the wrapper interface, for free. 在这种情况下,std :: list的所有标准构造函数都可以在包装器接口中免费获得。 Furthermore, for completeness, also WrapperCompos variation is proposed, where the list is contained into the wrapper, which exposes what is needed to support iterator-based loop. 此外,为了完整性,还提出了WrapperCompos变体,其中列表包含在包装器中,它公开了支持基于迭代器的循环所需的内容。 In this case, only the 'number of default elements' constructor is re-defined from scratch. 在这种情况下,只从头开始重新定义“默认元素数量”构造函数。

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

The private inheritance approach can be interesting to easily, and correctly, propagate the features of the wrapped structure to the wrapper. 私有继承方法可以很容易地,并且正确地将包装结构的特征传播到包装器。 For instance the wrapper can be easily made compatible with std::algorithms if the wrapped structure is compatible with them, like std::list is. 例如,如果包装结构与它们兼容,则包装器可以很容易地与std :: algorithms兼容,就像std :: list一样。 Hope this helps. 希望这可以帮助。 Best 最好

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM