为包装列表自定义迭代器

Customize an iterator for a wrapped list

本文关键字:迭代器 自定义 列表 包装      更新时间:2023-10-16

我有一个类memberlist,它包含类memberinfo的std::list。这些表示网络上的对等体。

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

我想公开一些迭代器(begin和end),这样外部代码就可以在我的内部列表中循环并读取它们的数据。然而,我希望有两种方法来实现这一点——一种方法包括localhost的元素,另一种方法不包括。

做这件事的好方法是什么?

我可以先放本地节点,然后像begin(showlocal=false)一样只给第二个元素,而不是第一个元素。或者有人建议存储一双bool,并说明它是本地的还是非本地的。

有什么好方法的建议吗?我还不太擅长高级STL的东西。

就我个人而言,我会用不同的方式来处理这个问题,并让您的memberinfo有一种方法来告诉您它是否是本地的。

这样一来,由于所包含对象的专业化,您就不会专门化您的收藏类。事实上,您可以使用标准的std::list<memberinfo>

例如

class memberinfo
{
    bool IsLocal( ) const;
}

然后,在遍历包含的对象时,您可以选择是否对本地成员感兴趣。

例如

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

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

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

#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,它会擦除底层迭代器类型。