开发者

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 multi-index container 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 construct an index on .bar().property() for a container of Foo objects?

Normally I would nest calls to boost::bind, but I开发者_StackOverflow can't figure out how to make it work in the context of a multi-index container.


Rather than providing a user-defined comparator, you can write a user-defined key extractor:

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


I believe you need to create a predicate object that takes two instances of Foo and its operator() can call Foo::bar() on 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>,
...

Check out MultiIndex Ordered indices reference


As much as I like using lambdas to do simple things, this can quickly degenerate :)

In your case, since it's a bit more complicated, I would rely either on a free function or a predicate comparator.

The predicate has the advantage of defining types more clearly so it's usually easier to actually bring it in.

Also, for readability's sake, I usually typedef 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 to nicely separate the comparison logic from the index definition, which is itself separated from the container definition.

Clear separation makes it easier to view the structure at a glance.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜