为包装列表自定义迭代器

时间:2012-09-14 14:41:49

标签: c++ list class stl

我有一个类,成员列表,其中包含{member}的{member}信息。这些代表了网络上的同伴。

我使用该类向列表中添加一些功能。

我想暴露一些迭代器(开始和结束),以便外部代码可以遍历我的内部列表并读取它们的数据。但是,我想有两种方法 - 一种包含localhost的元素,另一种不包含。

这样做的好方法是什么?

我可以先放置本地节点,然后像std::list那样只给第二个元素而不是第一个元素。或者有人建议存放一对bool,如果它是本地的话。

有关良好方法的任何建议吗?我对高级begin(showlocal=false)的东西还不太好。

2 个答案:

答案 0 :(得分:4)

就我个人而言,我会以不同的方式处理这个问题,让你的memberinfo有办法告诉你它是否是本地的。

这样,由于所包含对象的特化,您不会专门化您的集合类。实际上,您可以使用标准std::list<memberinfo>

E.g。

class memberinfo
{
    bool IsLocal( ) const;
}

然后,当您迭代所包含的对象时,您会选择是否对本地成员感兴趣。

E.g。

std::list<memberinfo>::iterator it;
std::list<memberinfo> list;

for ( it = list.begin() ; it != list.end() ; it++ )
{
    if ( it->IsLocal() )
    { 
        // blah blah blah
    }
    else
    {
        // dum dee dum dee
    }
}

答案 1 :(得分:0)

正如我在评论中所说,我认为你的第一个解决方案是合理的。但是,我不确定为begin提供参数是区分这两种情况的最佳方法。这个问题的主要问题是你不能将你的完整集合(包括localhost成员)用作范围,这意味着你不能使用Boost.Range algorithms或基于C ++ 11范围的for循环。

一个简单的解决方案是让两个不同的成员函数返回适当的范围,作为一对迭代器。 Boost.Range提供了sub_range class,这似乎相当合适(您希望返回成员列表的子范围)。以下是使用此方法的示例代码:

#include <boost/range.hpp>

#include <iostream>
#include <string>
#include <vector>

struct MemberInfo
{
    std::string name;
};

class MemberList
{
  public:

    typedef std::vector<MemberInfo>::iterator iterator;
    typedef std::vector<MemberInfo>::const_iterator const_iterator;

    MemberList() 
      : members_{MemberInfo{"local"}, MemberInfo{"foo"}, MemberInfo{"bar"}}
    {}

    boost::sub_range<std::vector<MemberInfo>> all() // includes localhost
    {
        return boost::sub_range<std::vector<MemberInfo>>(
            members_.begin(), members_.end());
    }

    boost::sub_range<std::vector<MemberInfo> const> all() const
    {
        return boost::sub_range<std::vector<MemberInfo> const>(
            members_.begin(), members_.end());
    }

    boost::sub_range<std::vector<MemberInfo>> some() // excludes localhost
    {
        return boost::sub_range<std::vector<MemberInfo>>(
            ++members_.begin(), members_.end());
    }

    boost::sub_range<std::vector<MemberInfo> const> some() const
    {
        return boost::sub_range<std::vector<MemberInfo> const>(
            ++members_.begin(), members_.end());
    }

  private:

    std::vector<MemberInfo> members_;
};

现在,您可以使用all()some(),具体取决于您是否要包含local,并且两者都可以用作范围:

int main()
{
    MemberList ml;

    for (MemberInfo mi : ml.all()) { std::cout << mi.name << '\n'; }

    for (MemberInfo mi : ml.some()) { std::cout << mi.name << '\n'; }
}

当然,你仍然可以像往常一样使用迭代器:

std::find_if(ml.all().begin(), ml.all().end(), ...);

如果您不想泄露成员存储在std::vector中的事实,可以使用any_range来删除底层迭代器类型。