Boost :: Multi-index用于嵌套列表 [英] Boost::Multi-index for nested lists

查看:66
本文介绍了Boost :: Multi-index用于嵌套列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何在列表列表上实现Boost :: Multi-index

我有一个如下的分层树:

  typedef std :: list< struct obj>objList//对象列表typedef std :: list< objList>topLevelList//顶级对象列表的列表结构对象{int ID;//全局唯一IDstd :: string objType;std :: string objAttributes;....topLevelList childObjectlist;} 

在顶层,我有一个struct obj的std :: list这样,每个顶级obj都可以具有任意数量的子对象,包含在该对象的topLevelList列表中.这可以继续,嵌套列表中的一个子项也有其自己的子项.

某些对象只能是子对象,而其他对象是容器,可以拥有自己的子对象.容器对象具有X个子容器,每个子容器都有其自己的子对象列表,这就是为什么我在每个obj结构中都具有topLevelList而不是简单的objList的原因.

我想使用boost :: Multi-index对列表列表进行索引,以通过其全局唯一ID随机访问顶级列表或后代列表中的任何对象.

这可以实现吗?我搜索了没有成功的示例.

我认为按对象ID使主搜索索引平坦的唯一方法是使上面的列表成为指向对象的指针的列表,然后遍历完整的层次结构列表,然后将指针登录到主搜索索引中每个对象都物理分配在内存中.然后可以通过主搜索索引找到任何对象.

使用Boost :: Multi-index,我仍然必须遍历层次结构,尽管希望能够在遇到的每个列表中使用随机而不是顺序访问来找到所需的对象.

使用嵌套向量而不是列表是一个问题-由于向量中会发生添加和删除,因此会降低性能,并且随着向量的重新分配,指向对象的指针可能会失效.

除非有人有更好的解决方案可以利用Boost :: Multi-index,否则我几乎要说服自己实现扁平化的objId主指针搜索索引.

在1/31/2020上进行我在执行下面的嵌套列表时遇到麻烦.在某些情况下,代码没有正确地将顶级父对象放置到顶级中,因此在括弧式"打印输出中,我们看不到该父级的层次结构.但是,在"xxx的子代"打印输出中,该父代的子代确实可以正确显示.这是main.cpp的一部分,演示了该问题:

  auto it = c.insert({170}).first;it = c.insert({171}).first;it = c.insert({172}).first;it = c.insert({173}).first;自动it141 = c.insert({141}).first;自动it137 = insert_under(c,it141,{137}).first;insert_under(c,it137,{8});insert_under(c,it137,{138});自动it9 = insert_under(c,it137,{9}).自动it5 = insert_under(c,it9,{5}).insert_under(c,it5,{6});insert_under(c,it5,{7});insert_under(c,it137,{142});自动it143 = insert_under(c,it137,{143}).first;insert_under(c,it143,{144}); 

如果将此代码放置在Main.cpp中而不是演示代码中并运行它,您将看到问题.对象141是父对象,并且被放置在顶层.但是,它不会在括弧式"层次结构打印输出中打印.为什么会这样?

在2020年2月2日

Boost :: Serialize通常会在归档时产生异常,抱怨重新创建特定对象会导致对象重复.一些档案成功保存并重新加载,但许多档案导致上述错误.我还无法确定发生错误的确切条件,但是我已经证明用于填充nested_container和平面对象列表的内容中的都包含重复的对象ID.我正在使用文本存档,而不是二进制文件.这是我如何修改nested_container以及另一个单独的平面对象列表的代码,以进行Boost :: Serialize:

  struct obj{int id;const obj * parent = nullptr;obj():id(-1){}obj(int对象):id(对象){}int getObjId()常量{返回ID;}布尔运算符==(obj obj2){如果(this-> getObjId()== obj2.getObjId())返回true;别的返回false;}#if 1私人的:朋友类boost :: serialization :: access;朋友std :: ostream&运算符<<(std :: ostream& os,const obj& obj);template< class Archive>无效序列化(归档& ar,const unsigned int file_version){ar&编号&父母}#万一};结构subtree_obj{常量对象obj_;subtree_obj(const obj& ob):obj_(ob){}#if 1私人的:朋友类boost :: serialization :: access;朋友std :: ostream&运算符<<(std :: ostream& os,const subtree_obj& obj);template< class Archive>无效序列化(归档& ar,const unsigned int file_version){ar&obj_;}#万一};结构路径{int id;const path * next = nullptr;路径(int ID,const path * nex):id(ID),next(nex){}路径(整数ID):id(ID){}#if 1私人的:朋友类boost :: serialization :: access;朋友std :: ostream&运算符<((std :: ostream& os,const path& pathe);template< class Archive>无效序列化(归档& ar,const unsigned int file_version){ar&编号&下一个;}#万一};struct subtree_path{常量路径小路_;subtree_path(常量路径和路径):path_(路径){}#if 1私人的:朋友类boost :: serialization :: access;朋友std :: ostream&运算符<((std :: ostream& os,const subtree_path& pathe);template< class Archive>无效序列化(归档& ar,const unsigned int file_version){ar&小路_;}#万一};////我的展平对象列表//结构HMIObj{int objId;std :: string objType;HMIObj():objId(-1),objType("){}bool运算符==(HMIObj obj2){如果(this-> getObjId()== obj2.getObjId())&&this-> getObjType()== obj2.getObjType())返回true;别的返回false;}int getObjId()常量{返回objId;}std :: string getObjType()常量{返回objType;}#if 1私人的:朋友类boost :: serialization :: access;朋友std :: ostream&运算符<((std :: ostream& os,const HMIObj& obj);template< class Archive>无效序列化(归档& ar,const unsigned int file_version){ar&objId&objType;}#万一}; 

解决方案

如果有帮助,您可以使用Boost.MultiIndex使用路径排序的概念来实现一种分层容器./p>

假设我们具有以下由对象ID标识的对象层次结构:

  | -------||0 4| ---- | ----||||||1 2 3 5 8 9|-||6 7 

我们将每个对象的路径定义为从根到对象的ID序列:

  0->01->0,12->0、23->0、34->45->4、56->4 5 67->4 5 78->4、89->4、9 

这些路径可以按字典顺序排序,因此按路径排序的对象序列实际上是底层层次结构的表示.如果我们添加指向对象的 parent 指针以建模父子关系:

  struct obj{int id;const obj * parent = nullptr;}; 

然后我们可以定义一个 multi_index_container ,该ID既可以通过ID进行O(1)访问,又可以基于层次结构进行索引:

  using nested_container = multi_index_container<obj,indexed_by<hashed_unique< member< obj,int,& obj :: id>> ;,ordered_unique< identity< obj>,obj_less>>> ;; 

其中, obj_less 根据路径顺序比较对象.如下例所示,所有类型的树操作和访问都是可能的(代码并非完全无关紧要,请随时询问).

在Coliru上直播

  #include< boost/multi_index_container.hpp>#include< boost/multi_index/hashed_index.hpp>#include< boost/multi_index/ordered_index.hpp>#include< boost/multi_index/identity.hpp>#include< boost/multi_index/member.hpp>#include< iterator>结构对象{int id;const obj * parent = nullptr;};结构subtree_obj{常量对象obj_;};结构路径{int id;const path * next = nullptr;};struct subtree_path{const path&小路_;};内联布尔运算符<(const path& x,const path& y){if(x.id< y.id)返回true;否则if(y.id< x.id)返回false;否则if(!x.next)返回y.next;否则if(!y.next)返回false;否则返回*(x.next)< *(y.next);}内联布尔运算符<(const subtree_path& sx,const path& y){const path&x = sx.path_;if(x.id< y.id)返回true;否则if(y.id< x.id)返回false;否则if(!x.next)返回false;否则if(!y.next)返回false;否则返回subtree_path {*(x.next)}< *(y.next);}内联布尔运算符<(const path& x,const subtree_path& sy){返回x< sy.path_;}结构obj_less{私人的:模板< typename F>静态自动apply_to_path(const obj& x,F f){返回apply_to_path(x.parent,path {x.id},f);}模板< typename F>静态自动apply_to_path(const obj * px,const path& x,F f)-> decltype(f(x)){return!px?f(x):apply_to_path(px-> parent,{px-> id,& x},f);}上市:布尔运算符()(const obj& x,const obj& y)const{返回apply_to_path(x,[&](const path& x){返回apply_to_path(y,[&](const path& y){返回x< y;});});}布尔运算符()(const subtree_obj& x,const obj& y)const{返回apply_to_path(x.obj _,[&](const path& x){返回apply_to_path(y,[&](const path& y){返回subtree_path {x}< y;});});}布尔运算符()(const obj& x,const subtree_obj& y)const{返回apply_to_path(x,[&](const path& x){返回apply_to_path(y.obj _,[&](const path& y){返回x< subtree_path {y};});});}};使用命名空间boost :: multi_index;使用nested_container = multi_index_container<obj,indexed_by<hashed_unique< member< obj,int,& obj :: id>> ;,ordered_unique< identity< obj>,obj_less>>> ;;template< typename Iterator>内联自动insert_under(nested_container& c,Iterator it,obj x){x.parent =& * it;返回c.insert(std :: move(x));}template< typename迭代器,typename F>无效的for_each_in_level(nested_container&c,迭代器优先,迭代器末尾,F f){if(first == last)return;const obj * parent = first-> parent;自动first_ = c.project< 1>(第一),last_ = c.project< 1>(last);做{f(* first_);自动next = std :: next(first_);if(next-> parent!= parent){next = c.get< 1>().upper_bound(subtree_obj {* first_});}first_ = next;} while(first _!= last_);}模板<类型名ObjPointer,类型名F>无效的for_each_child(nested_container& c,ObjPointer p,F f){自动[first,last] = c.get< 1>().equal_range(subtree_obj {* p});for_each_in_level(c,std :: next(first),last,f);}#include< iostream>自动打印= [](const obj& x){std :: cout<< x.id<<" ;;};无效的print_subtree(nested_container& c,const obj& x){std :: cout<< x.id<<"bool Visitd = false;for_each_child(c,& x,[&](const obj& x){if(!visited){std :: cout<<"[";visit = true;}print_subtree(c,x);});if(visited)std :: cout<<]]";}int main(){nested_container c;自动it = c.insert({0}).first;insert_under(c,it,{1});insert_under(c,it,{2});insert_under(c,it,{3});it = c.insert({4}).first;自动it2 = insert_under(c,it,{5}).insert_under(c,it2,{6});insert_under(c,it2,{7});insert_under(c,it,{8});insert_under(c,it,{9});std :: cout<<"preorder:\ t";std :: for_each(c.get< 1>().begin(),c.get< 1>().end(),print);std :: cout<<"\ n";std :: cout<<顶级:\ t";for_each_in_level(c,c.get< 1>().begin(),c.get< 1>().end(),print);std :: cout<<"\ n";std :: cout<<"0岁的孩子:\ t";for_each_child(c,c.find(0),print);std :: cout<<"\ n";std :: cout<<"4岁的孩子:\ t";for_each_child(c,c.find(4),print);std :: cout<<"\ n";std :: cout<<"5岁的孩子:\ t";for_each_child(c,c.find(5),print);std :: cout<<"\ n";std :: cout<<放在方括号中:\ t";for_each_in_level(c,c.get< 1>().begin(),c.get< 1>().end(),[&](const obj& x){print_subtree(c,x);});std :: cout<<"\ n";} 

输出

 预购:0 1 2 3 4 5 6 7 8 9最高层:0 40的孩子:1 2 34个孩子:5 8 95岁以下儿童:6 7方括号:0 [1 2 3] 4 [5 [6 7] 8 9] 

更新2020/02/02:

访问顶级元素时,我已将代码从以下位置更改:

  std :: for_each(c.begin(),c.end(),...;for_each_in_level(c,c.begin(),c.end(),...); 

  std :: for_each(c.get< 1>().begin(),c.get< 1>().end(),...;for_each_in_level(c,c.get< 1>().begin(),c.get< 1>().end(),...); 

这是因为索引#0被散列,并且不一定显示按ID排序的元素.

例如,如果按此顺序插入ID为(170,171,173,173,141)的元素,则索引#0将其列为

170,171,173,173,141(恰好与插入的顺序相同),

而索引1将它们列出为

141,170,171,173,173(按ID排序).

代码的实现方式, for_each_in_level(c,c.begin(),c.end(),...); 在内部映射到索引#1 范围[170,...,173],省略141.然后,确保包含所有顶级元素的方法是编写 for_each_in_level(c,c.get< 1>().begin(),c.get< 1>().end(),...); .

How to implement Boost::Multi-index on a list of lists

I have a hierarchical tree as follows:

typedef std::list<struct obj> objList // the object list
typedef std::list<objList> topLevelList // the list of top-level object lists

struct obj
{
   int Id; // globally unique Id
   std::string objType;
   std::string objAttributes;
   ....
   topLevelList  childObjectlist;
}

At the top-level, I have a std::list of struct obj Then, each of these top-level obj can have any number of child objects, which are contained in a topLevelList list for that object. This can continue, with a child in the nested list also having its own children.

Some objects can only be children, while others are containers and can have children of their own. Container objects have X number of sub-containers, each sub-container having its own list of child objects and that is why I have topLevelList in each obj struct, rather than simply objList.

I want to index this list of lists with boost::Multi-index to obtain random access to any of the objects in either the top-level list or the descendant list by its globally unique Id.

Can this be accomplished? I have searched for examples with no success.

I think the only way to have a flattened master search index by object Ids is to make the lists above to be lists of pointers to the objects, then traverse the completed hierarchical list, and log into the master search index the pointer where each object is physically allocated in memory. Then any object can be located via the master search index.

With Boost::Multi-index, I'd still have to traverse the hierarchy, though hopefully with the ability to use random instead of sequential access in each list encountered, in order to find a desired object.

Using nested vectors instead of lists is a problem - as additions and deletions occur in the vectors, there is a performance penalty as well as the prospect of pointers to objects becoming invalidated as the vectors are reallocated.

I'm almost talking myself into implementing the flattened master objId search index of pointers, unless someone has a better solution that can leverage Boost::Multi-index.

Edit on 1/31/2020: I'm having trouble with the implementation of nested lists below. I have cases where the code does not properly place top-level parent objects into the top level, and thus in the "bracketed" printout, we don't see the hierarchy for that parent. However, in the "Children of xxx" printout, the children of that parent do display correctly. Here is a section of main.cpp which demonstrates the problem:

auto it=c.insert({170}).first;
it=c.insert({171}).first;
it=c.insert({172}).first;
it=c.insert({173}).first;
auto it141=c.insert({141}).first;
    auto it137=insert_under(c,it141,{137}).first;
        insert_under(c,it137,{8});
        insert_under(c,it137,{138});
        auto it9=insert_under(c,it137,{9}).first;
            auto it5=insert_under(c,it9,{5}).first;
                insert_under(c,it5,{6});
                insert_under(c,it5,{7});
        insert_under(c,it137,{142});
        auto it143=insert_under(c,it137,{143}).first;
        insert_under(c,it143,{144});

If you place this code in Main.cpp instead of the demo code and run it you will see the problem. Object 141 is a parent object and is placed at the top level. But it does not print in the "Bracketed" hierarchy printout. Why is this?

Edit on 2/2/2020:

Boost::Serialize often delivers an exception on oarchive, complaining that re-creating a particular object would result in duplicate objects. Some archives save and re-load successfully, but many result in the error above. I have not been able yet to determine the exact conditions under which the error occurs, but I have proven that none of the content used to populate the nested_container and the flat object list contains duplicate object IDs. I am using text archive, not binary. Here is how I have modified the code for nested_container and also for another, separate flat object list in order to do Boost::Serialize:

struct obj
{
    int             id;
    const obj * parent = nullptr;

    obj()
        :id(-1)
    { }

    obj(int object)
        :id(object)
    { }

    int getObjId() const
    {
        return id;
    }

    bool operator==(obj obj2)
    {
        if (this->getObjId() == obj2.getObjId())
            return true;
        else
            return false;
    }
#if 1
private:
    friend class boost::serialization::access;
    friend std::ostream & operator<<(std::ostream &os, const obj &obj);

    template<class Archive>
    void serialize(Archive &ar, const unsigned int file_version)
    {
        ar & id & parent;
    }
#endif
};

struct subtree_obj
{
    const obj & obj_;

    subtree_obj(const obj & ob)
        :obj_(ob)
    { }
#if 1
private:
    friend class boost::serialization::access;
    friend std::ostream & operator<<(std::ostream &os, const subtree_obj &obj);

    template<class Archive>
    void serialize(Archive &ar, const unsigned int file_version)
    {
        ar & obj_;
    }
#endif
};

struct path
{
    int         id;
    const path *next = nullptr;

    path(int ID, const path *nex)
        :id(ID), next(nex)
    { }

    path(int ID)
        :id(ID)
    { }
#if 1
private:
    friend class boost::serialization::access;
    friend std::ostream & operator<<(std::ostream &os, const path &pathe);

    template<class Archive>
    void serialize(Archive &ar, const unsigned int file_version)
    {
        ar & id & next;
    }
#endif
};

struct subtree_path
{
    const path & path_;

    subtree_path(const path & path)
        :path_(path)
    { }
#if 1
private:
    friend class boost::serialization::access;
    friend std::ostream & operator<<(std::ostream &os, const subtree_path &pathe);

    template<class Archive>
    void serialize(Archive &ar, const unsigned int file_version)
    {
        ar & path_;
    }
#endif
};

//
// My flattened object list
//

struct HMIObj
{
    int         objId;
    std::string objType;

    HMIObj()
        :objId(-1), objType("")
    { }

    bool operator==(HMIObj obj2)
    {
        if (this->getObjId() == obj2.getObjId())
            && this->getObjType() == obj2.getObjType())
            return true;
        else
            return false;
    }

    int getObjId() const
    {
        return objId;
    }

    std::string getObjType() const
    {
        return objType;
    }
#if 1
private:
    friend class boost::serialization::access;
    friend std::ostream & operator<<(std::ostream &os, const HMIObj &obj);

    template<class Archive>
    void serialize(Archive &ar, const unsigned int file_version)
    {
        ar & objId & objType;
    }
#endif
};

解决方案

In case it helps, you can use Boost.MultiIndex to implement a sort of hierarchical container using the notion of path ordering.

Suppose we have the following hierarchy of objects, identified by their IDs:

|-------
|      |
0      4
|----  |----
| | |  | | |
1 2 3  5 8 9
       |--
       | |
       6 7

We define the path of each object as the sequence of IDs from the root down to the object:

0 --> 0
1 --> 0, 1
2 --> 0, 2
3 --> 0, 3
4 --> 4
5 --> 4, 5
6 --> 4, 5, 6
7 --> 4, 5, 7
8 --> 4, 8
9 --> 4, 9

These paths can be ordered lexicographically so that a sequence of objects sorted by path is actually a representation of the underlying hierarchy. If we add a parent pointer to objects to model parent-child relationships:

struct obj
{
   int        id;
   const obj* parent=nullptr;
};

then we can define a multi_index_container with both O(1) access by ID and hierarchy-based indexing:

using nested_container=multi_index_container<
  obj,
  indexed_by<
    hashed_unique<member<obj,int,&obj::id>>,
    ordered_unique<identity<obj>,obj_less>
  >
>;

where obj_less compares objects according to path ordering. All types of tree manipulations and visitations are possible as exemplified below (code is not entirely trivial, feel free to ask).

Live On Coliru

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/member.hpp>
#include <iterator>

struct obj
{
   int        id;
   const obj* parent=nullptr;
};

struct subtree_obj
{
  const obj& obj_;
};

struct path
{
  int         id;
  const path* next=nullptr;
};

struct subtree_path
{
  const path& path_;
};

inline bool operator<(const path& x,const path& y)
{
       if(x.id<y.id)return true;
  else if(y.id<x.id)return false;
  else if(!x.next)  return y.next;
  else if(!y.next)  return false;
  else              return *(x.next)<*(y.next);
}

inline bool operator<(const subtree_path& sx,const path& y)
{
  const path& x=sx.path_;

       if(x.id<y.id)return true;
  else if(y.id<x.id)return false;
  else if(!x.next)  return false;
  else if(!y.next)  return false;
  else              return subtree_path{*(x.next)}<*(y.next);
}

inline bool operator<(const path& x,const subtree_path& sy)
{
  return x<sy.path_;
}

struct obj_less
{
private:
  template<typename F>
  static auto apply_to_path(const obj& x,F f)
  {
    return apply_to_path(x.parent,path{x.id},f); 
  }

  template<typename F>
  static auto apply_to_path(const obj* px,const path& x,F f)
    ->decltype(f(x))
  { 
    return !px?f(x):apply_to_path(px->parent,{px->id,&x},f);
  }

public:
  bool operator()(const obj& x,const obj& y)const
  {
    return apply_to_path(x,[&](const path& x){
      return apply_to_path(y,[&](const path& y){
        return x<y;
      });
    });
  }

  bool operator()(const subtree_obj& x,const obj& y)const
  {
    return apply_to_path(x.obj_,[&](const path& x){
      return apply_to_path(y,[&](const path& y){
        return subtree_path{x}<y;
      });
    });
  }

  bool operator()(const obj& x,const subtree_obj& y)const
  {
    return apply_to_path(x,[&](const path& x){
      return apply_to_path(y.obj_,[&](const path& y){
        return x<subtree_path{y};
      });
    });
  }
};

using namespace boost::multi_index;
using nested_container=multi_index_container<
  obj,
  indexed_by<
    hashed_unique<member<obj,int,&obj::id>>,
    ordered_unique<identity<obj>,obj_less>
  >
>;

template<typename Iterator>
inline auto insert_under(nested_container& c,Iterator it,obj x)
{
  x.parent=&*it;
  return c.insert(std::move(x));
}

template<typename Iterator,typename F>
void for_each_in_level(
  nested_container& c,Iterator first,Iterator last, F f)
{
  if(first==last)return;

  const obj* parent=first->parent;
  auto       first_=c.project<1>(first),
             last_=c.project<1>(last);

  do{
    f(*first_);
    auto next=std::next(first_);
    if(next->parent!=parent){
      next=c.get<1>().upper_bound(subtree_obj{*first_});
    }
    first_=next;
  }while(first_!=last_);
}

template<typename ObjPointer,typename F>
void for_each_child(nested_container& c,ObjPointer p,F f)
{
  auto [first,last]=c.get<1>().equal_range(subtree_obj{*p});
  for_each_in_level(c,std::next(first),last,f);
}

#include <iostream>

auto print=[](const obj& x){std::cout<<x.id<<" ";};

void print_subtree(nested_container& c,const obj& x)
{
  std::cout<<x.id<<" ";
  bool visited=false;
  for_each_child(c,&x,[&](const obj& x){
    if(!visited){
      std::cout<<"[ ";
      visited=true;
    }
    print_subtree(c,x);
  });
  if(visited)std::cout<<"] ";
}

int main()
{
  nested_container c;
  auto it=c.insert({0}).first;
    insert_under(c,it,{1});
    insert_under(c,it,{2});
    insert_under(c,it,{3});
  it=c.insert({4}).first;
    auto it2=insert_under(c,it,{5}).first;
      insert_under(c,it2,{6});
      insert_under(c,it2,{7});
    insert_under(c,it,{8});
    insert_under(c,it,{9});

  std::cout<<"preorder:\t";
  std::for_each(c.get<1>().begin(),c.get<1>().end(),print);  
  std::cout<<"\n"; 

  std::cout<<"top level:\t";
  for_each_in_level(c,c.get<1>().begin(),c.get<1>().end(),print);
  std::cout<<"\n"; 

  std::cout<<"children of 0:\t";
  for_each_child(c,c.find(0),print);
  std::cout<<"\n";

  std::cout<<"children of 4:\t";
  for_each_child(c,c.find(4),print);
  std::cout<<"\n";

  std::cout<<"children of 5:\t";
  for_each_child(c,c.find(5),print);
  std::cout<<"\n"; 

  std::cout<<"bracketed:\t";
  for_each_in_level(c,c.get<1>().begin(),c.get<1>().end(),[&](const obj& x){
    print_subtree(c,x);
  });
  std::cout<<"\n"; 
}

Output

preorder:       0 1 2 3 4 5 6 7 8 9 
top level:      0 4 
children of 0:  1 2 3 
children of 4:  5 8 9 
children of 5:  6 7 
bracketed:      0 [ 1 2 3 ] 4 [ 5 [ 6 7 ] 8 9 ] 

Update 2020/02/02:

When accessing top-level elements, I've changed the code from:

std::for_each(c.begin(),c.end(),...;  
for_each_in_level(c,c.begin(),c.end(),...);

to

std::for_each(c.get<1>().begin(),c.get<1>().end(),...;  
for_each_in_level(c,c.get<1>().begin(),c.get<1>().end(),...);

This is because index #0 is hashed and does not necessarily show elements sorted by ID.

For instance, if elements with IDs (170,171,173,173,141) are inserted in this order, index #0 lists them as

170,171,173,173,141 (coincidentally, same order as inserted),

while index #1 lists them as

141,170,171,173,173 (sorted by ID).

The way the code is implemented, for_each_in_level(c,c.begin(),c.end(),...); gets internally mapped to index #1 range [170,...,173], leaving out 141. The way to make sure all top elements are included is then to write for_each_in_level(c,c.get<1>().begin(),c.get<1>().end(),...);.

这篇关于Boost :: Multi-index用于嵌套列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆