将Boost Filter Iterator与非原始对象一起使用

时间:2014-07-21 17:36:00

标签: c++ boost

假设我有一个来自Boost多重索引的返回迭代器,其中每个记录包含一个年龄和一个名称字段。

我用

获取迭代器
auto& index = get<age>(m_records);
auto ibegin = index.begin();
auto iend = index.end();

我如何在Boost的Filter Iterator中使用这个迭代器,这样我就可以返回所有记录,比如名字=&#34; John&#34;?

我为谓词运算符设置了一个结构,我不确定它是否正确:

struct name_equal_to {
      std::string struct_sname;
      bool operator()(ServerRecord x) { return x.get_name() == struct_sname; }
      name_equal_to(std::string in) : struct_sname(in){}
   };

2 个答案:

答案 0 :(得分:4)

我使用过滤后的适配器,使事情更具可读性:

for (auto& r : get<age>(m_records) | filtered(name_equal_to("John"))
    std::cout << r << "\n";

我在风格上改进了仿函数( Live On Coliru ):

struct name_equal_to {
    bool operator()(ServerRecord const& x) const { 
        return x.get_name() == sname_; 
    }
    name_equal_to(std::string in) : sname_(std::move(in)){}
  private:
    std::string sname_;
};

为了使它真正优雅,使用Phoenix来就地定义谓词named_john

auto named_john = phx::bind(&record::name, arg1) == "John";

查看 Live On Coliru ,其中会打印按年龄索引排序的两条记录:

2 John 40
4 John 57

完整示例代码

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/range/iterator_range.hpp>
#include <iostream>

using boost::multi_index_container;
using namespace boost::multi_index;

struct record {
    int         id;
    std::string name;
    int         age;

    friend std::ostream& operator<<(std::ostream& os,const record& e) {
        return os << e.id << " " << e.name << " " << e.age;
    }
};

typedef multi_index_container<
  record,
  indexed_by<
    ordered_unique<tag<struct id>      , BOOST_MULTI_INDEX_MEMBER(record, int        , id)>   ,
    ordered_non_unique<tag<struct name>, BOOST_MULTI_INDEX_MEMBER(record, std::string, name)> ,
    ordered_non_unique<tag<struct age> , BOOST_MULTI_INDEX_MEMBER(record, int        , age)> >
> employee_set;


employee_set get_records()
{
    employee_set es;

    es.insert(record{ 0,       "Joe",   31 });
    es.insert(record{ 1,    "Robert",   27 });
    es.insert(record{ 2,      "John",   40 });
    // next insertion will fail, as there is an record with the same ID
    es.insert(record{ 2, "Aristotle", 2387 });
    es.insert(record{ 3,    "Albert",   20 });
    es.insert(record{ 4,      "John",   57 });

    return es;
}

#include <boost/phoenix.hpp>
#include <boost/range/adaptors.hpp>
namespace phx = boost::phoenix;
using namespace phx::arg_names;
using boost::adaptors::filtered;

int main()
{
    auto const m_records = get_records();

    auto named_john = phx::bind(&record::name, arg1) == "John";

    for (auto& r : get<age>(m_records) | filtered(named_john)) {
        std::cout << r << "\n";
    };
}

答案 1 :(得分:3)

@ sehe的答案是绝对正确的,但是如果你关心效率,那么这不是检索按年龄排序的所有Johns的最快方法。假设您的容器中有 N 个元素,其中包含 M Johns。所以:

  1. 遍历按年龄排序的所有元素并按“John”过滤需要 N 步骤。
  2. 检索所有Johns并按年龄排序(如your other post中所述)需要(大致)2·log( N )步骤来检索Johns的范围,一个临时分配vector, M 填充它的步骤,O( M ·log( M ))对它进行排序, M 遍历它。
  3. 因此,它是O( N )与O(log( N )+ M ·log( M < / em>的))。我敢打赌#em> M &lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt; N ,我认为这是通常的情况(当然你应该衡量你的实际节目)。