繁体   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