Boost multi-index container with index based on nested values

If I have an object like this:

struct Bar { std::string const& property(); }; 

I can create a container with multiple indices for it like this:

 struct tag_prop {}; typedef boost::multi_index_container< Bar, boost::multi_index::indexed_by< boost::multi_index::ordered_non_unique< boost::multi_index::tag<tag_prop>, boost::multi_index::const_mem_fun< Bar, const std::string&, &Bar::property > > > , ... other indexes > BarContainer; 

But if I have a class like this:

 struct Foo { Bar const& bar(); }; 

How can I build an index on .bar().property() for a container of Foo objects?

Normally, I would introduce calls to boost::bind , but I cannot figure out how to make it work in the context of a container with multiple indices.

+6
c ++ boost nested multi-index
source share
3 answers

I believe that you need to create a predicate object that accepts two instances of Foo, and its operator () can call Foo :: bar () for both instances.

Something like

 struct MyPredicate { bool operator() (const Foo& obj1, const Foo& obj2) const { // fill in here } }; 

and then use

 ... boost::multi_index::ordered_unique<boost::multi_index::tag<tag_prop>, boost::multi_index::identity<Foo>, MyPredicate>, ... 

Mark Link to MultiIndex Index Pointers

+5
source share

Instead of providing a custom comparator, you can write a user-defined extractor key:

  struct FooBarPropertyExtractor
 {
   typedef std :: string result_type;
   const result_type & oeprator () (const Foo & f)
   {
     return f.bar (). property ();
   }
 };

 ...

 typedef boost :: multi_index_container <
         Bar
         boost :: multi_index :: indexed_by <
                 boost :: multi_index :: ordered_non_unique <
                         boost :: multi_index :: tag <tag_prop>,
                         FooBarPropertyExtractor
                 >
         >
         , ... other indexes
 > FooContainer;

See Advanced Features of Boost.MultiIndex Key Extractors

+6
source share

As far as I like to use lambda to do simple things, it can degenerate quickly :)

In your case, since this is a little more complicated, I would rely on either a free function or a predicate comparator.

The advantage of a predicate is to define types more clearly so that it is usually easier to enter.

In addition, for readability, I usually type in my indexes, which gives:

 namespace mi = boost::multi_index; struct FooComparator { bool operator()(Foo const& lhs, Foo const& rhs) const { return lhs.bar().property() < rhs.bar().property(); } }; typedef mi::ordered_unique < mi::tag<tag_prop>, mi::identity<Foo>, FooComparator > foo_bar_index_t; typedef boost::multi_index_container < Foo, mi::indexed_by < foo_bar_index_t, // ... other indexes > > foo_container_t; 

The predicate approach requires more boilerplate code, but it allows you to perfectly separate the comparison logic from the index definition, which itself is separate from the container definition.

Clear separation makes it easy to see the structure at a glance.

+1
source share

All Articles