c++ - 使用组合键、自定义比较器和部分索引搜索来 boost multi_index 容器

标签 c++ boost boost-multi-index

我有一个这样的类(简化示例):

class A {
  public:
    typedef boost::shared_ptr<A> Ptr;
    const std::string& getID() const;
    const std::string& getLabel() const;
    bool getFlag() const;
    float getValue() const;
  private:
  ...
};

我需要一个由 (id, label) 的唯一组合索引的容器也是 (label, flag, value) 的独特组合.我还需要它按第二个索引排序,首先是标签,然后是标志,如果标志为真,则递减值;如果标志为假,则递增值。所以在创建 key 提取器之后,我正在做这样的事情:

typedef boost::multi_index::composite_key<
  Ptr, extractor_id, extractor_label
> id_label_key;
typedef boost::multi_index::composite_key<
  Ptr, extractor_label, extractor_flag, extractor_value
> label_flag_value_key;
...
typedef boost::multi_index_container<Ptr,
  boost::multi_index::indexed_by<
    boost::multi_index::ordered_unique<
      boost::multi_index::tag<by_id_label
      id_label_key
    >,
    boost::multi_index::ordered_unique<
      boost::multi_index::tag<by_label_flag_value>,
      label_flag_value_key,
      Compare
    >,
  >
> Items;
typedef Items::index<by_label_flag_value>::type Items_by_label_flag_value;

其中比较定义为:

struct Compare {
  bool operator() (const boost::multi_index::composite_key_result<label_flag_value_key>& k, const boost::tuple<float,bool>& q) const {
    return compare(k.value->getLabel(), k.value->getFlag(), k.value->getValue(),
      q.get<0>(), q.get<1>(), q.get<2>()
  }
  bool operator() (const boost::tuple<float,bool>& q, const boost::multi_index::composite_key_result<label_flag_value_key>& k) const {
    return compare(q.get<0>(), q.get<1>(), q.get<2>(), 
      k.value->getLabel(), k.value->getFlag(), k.value->getValue(),
  }
  bool operator() (const boost::multi_index::composite_key_result<label_flag_value_key>& k1, const boost::multi_index::composite_key_result<label_flag_value_key>& k2) const {
    return compare(k1.value->getLabel(), k1.value->getFlag(), k1.value->getValue(),
      k2.value->getLabel(), k2.value->getFlag(), k2.value->getValue())
  }
  bool compare(const std::string& l1, bool f1, float v1, const std::string& l2, bool f2, float v2) const {
    if (l1 != l2) return l1 < l2;
    if (f1 != f2) return f1;
    return f1 ? (v1 > v2) : (v1 < v2);
  }
};

现在,我可以执行这样的查询:

Items_by_label_flag_value::const_iterator it = items_by_label_flag_value.find(boost::make_tuple("A", true, 0.1));

但是,如果我尝试执行部分查询 - 例如,检索具有相同标签的所有项目 - 我的代码将无法编译:

std::pair<Items_by_label_flag_value::const_iterator, Items_by_label_flag_value::const_iterator> range = items_by_label_flag_value.equal_range(boost::make_tuple("A"));

我知道为什么它不能编译:在比较器中我明确地使用了 .get<0>() , .get<1>().get<2>()但部分搜索元组没有 <1><2>元素。我不知道的是如何创建正确的比较器。如果我尝试向它添加两个仅采用一个元素的元组的函数,那么编译器会提示 operator() 中的歧义。打电话。

我也明白composite_key_result应该是一个不透明的物体,我不应该使用它的内部。

所以我的问题是如何创建所需的索引和正确的比较器?

最佳答案

至于你原来的解决方案,你不需要为你的第二个索引使用复合键作为你的 Compare提取器基本上是在尝试替换 composite_key 自动生成的机器/composite_key_compare .以下内容已经过(轻微)测试可以正常工作:

struct LBFCompare
{
  bool operator() (const A& x, const A& y) const {
    return compare(
      x.getLabel(), x.getFlag(), x.getValue(),
      y.getLabel(), y.getFlag(), y.getValue());
  }
  bool operator() (const std::string& x, const A& y) const{
    return compare(x,y.getLabel());
  }
  bool operator() (const A& x, const std::string& y) const{
    return compare(x.getLabel(),y);
  }
  template<typename T0>
  bool operator() (const boost::tuple<T0>& x, const A& y) const{
    return compare(x.get<0>(),y.getLabel());
  }
  template<typename T0>
  bool operator() (const A& x, const boost::tuple<T0>& y) const{
    return compare(x.getLabel(),y.get<0>());
  }
  template<typename T0,typename T1>
  bool operator() (const boost::tuple<T0,T1>& x, const A& y) const{
    return compare(x.get<0>(),x.get<1>(),y.getLabel(),y.getFlag());
  }
  template<typename T0,typename T1>
  bool operator() (const A& x, const boost::tuple<T0,T1>& y) const{
    return compare(x.getLabel(),x.getFlag(),y.get<0>(),y.get<1>());
  }
  template<typename T0,typename T1,typename T2>
  bool operator() (const boost::tuple<T0,T1,T2>& x, const A& y) const{
    return compare(x.get<0>(),x.get<1>(),x.get<2>(),y.getLabel(),y.getFlag(),y.getValue());
  }
  template<typename T0,typename T1,typename T2>
  bool operator() (const A& x, const boost::tuple<T0,T1,T2>& y) const{
    return compare(x.getLabel(),x.getFlag(),x.getValue(),y.get<0>(),y.get<1>(),y.get<2>());
  }
  bool compare(const std::string& l1, const std::string& l2) const {
    return l1 < l2;
  }
  bool compare(const std::string& l1, bool f1, const std::string& l2, bool f2) const {
    if (l1 != l2) return l1 < l2;
    return f1 < f2;
  }
  bool compare(const std::string& l1, bool f1, float v1, const std::string& l2, bool f2, float v2) const {
    if (l1 != l2) return l1 < l2;
    if (f1 != f2) return f1;
    return f1 ? (v1 > v2) : (v1 < v2);
  }
};

struct by_id_label{};
struct by_label_flag_value{};

typedef boost::multi_index_container<
  Ptr,
  boost::multi_index::indexed_by<
    boost::multi_index::ordered_unique<
      boost::multi_index::tag<by_id_label>,
      id_label_key
    >,
    boost::multi_index::ordered_unique<
      boost::multi_index::tag<by_label_flag_value>,
      boost::multi_index::identity<A>,
      LBFCompare
    >
  >
> Items;
typedef Items::index<by_label_flag_value>::type Items_by_label_flag_value;

int main()
{
  Items c;
  c.insert(Ptr(new A("id","label",true,1.0)));
  Items_by_label_flag_value& i=c.get<by_label_flag_value>();
  i.find("id");
  i.find(boost::make_tuple("id"));
  i.find(boost::make_tuple("id",true));
  i.find(boost::make_tuple("id",true,1.0));
}

您提到的歧义问题是由于您可能通过使用 const char* 传递元组来进行查找。 s 而不是完整的 std::string s:在这种情况下,存在隐式转换,看起来 1、2 和 3 大小的元组同样是不错的候选者(恕我直言,这是元组的实现问题。)解决方案是将这些模板化 LBFCompare::operator() s 接受元组。

关于c++ - 使用组合键、自定义比较器和部分索引搜索来 boost multi_index 容器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16421901/

相关文章:

c++ - linux3/gcc46 : "-fnon-call-exceptions", 哪些信号是陷阱指令?

c++ - 如果我们已经有了 RVO, move 语义会提供什么优化?

c++ - boost::mpi 在具有相同标签的多个 isend/irecv 传输中抛出 MPI_ERR_TRUNCATE

c++ - boost::multi_index_container,对容器内 std::set 的操作

c++ - FILE_FLAG_DELETE_ON_CLOSE 和内存映射文件

c++ - 虚拟成员函数对于现代 CPU 中的局部性是好是坏?

c++ - BH R-package 可以链接到 boost "math"和 "numeric"吗?

c++ - 尝试用 Boost::Beast 替换我的 libwebsocket 代码

c++ - boost multi_index_container 更改键 -> 容器状态不正确

c++ - 获取 boost::multi_index 容器元素的等级