【问题标题】:Customize an iterator for a wrapped list为包装列表自定义迭代器
【发布时间】:2012-09-07 18:02:00
【问题描述】:

我有一个类 memberlist,其中包含一个 std::list 的类成员信息。这些代表网络上的对等点。

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

我想公开一些迭代器(开始和结束),以便外部代码可以循环通过我的内部列表并读取它们的数据。但是,我想有两种方法来做到这一点 - 一种包含 localhost 的元素,另一种不包含。

有什么好的方法可以做到这一点?

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

有什么好的方法可以做到这一点吗?我对高级STL 的东西还不是很了解。

【问题讨论】:

  • 您的第一个解决方案似乎很合适(在一种情况下将迭代器返回到第一个元素,在另一种情况下返回到第二个元素)。这可能不是最清晰的方法,但它具有简单的优点。如果你这样做,我认为一些 cmets 解释正在发生的事情会受到欢迎(明确第一个元素将始终对应于 localhost,并正确记录 begin 成员函数)。

标签: c++ list class stl


【解决方案1】:

就我个人而言,我会以不同的方式处理此问题,并让您的 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
    }
}

【讨论】:

  • 如果我理解正确,OP 希望对所有成员一视同仁,但有时包括特定成员(对应于 localhost),有时将其放在一边。我认为您提出的解决方案并不适合此目的。此外,它不太适合标准算法的基于迭代器的设计:要在某些计算中包含或排除本地成员,您需要某种过滤迭代器来测试当前成员是否为本地成员。 [...]
  • [...] 但是请注意,这可以通过 Boost.filter_iterator 和 lambdas(或 std::bind)很好地完成:auto it = boost::make_filter_iterator([](MemberInfo const &amp; mi) { return !mi.IsLocal(); }, list.begin(), list.end());
  • 我想这归结为对 O.P. 问题的解释。我倾向于围绕适用于手头问题的内容来设计我的软件,而不是适应基于 xyz 的设计原则。
【解决方案2】:

正如我在评论您的问题时所说,我认为您的第一个解决方案是合理的。但是,我不确定为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,它会清除底层迭代器类型。

【讨论】:

    猜你喜欢
    • 2015-05-19
    • 2014-10-24
    • 2017-07-25
    • 2015-02-04
    • 2014-08-07
    • 2020-01-03
    • 2013-02-17
    • 2021-02-27
    相关资源
    最近更新 更多