Увеличить многоиндексный контейнер с индексом, основанным на вложенных значениях - PullRequest
6 голосов
/ 27 октября 2009

Если у меня есть такой объект:

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

Я могу создать для него многоиндексный контейнер следующим образом:

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;

Но если у меня есть такой класс:

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

Как создать индекс на .bar().property() для контейнера из Foo объектов?

Обычно я вкладывал бы вызовы в boost::bind, но не могу понять, как заставить его работать в контексте многоиндексного контейнера.

Ответы [ 3 ]

6 голосов
/ 02 ноября 2009

Вместо предоставления пользовательского компаратора вы можете написать пользовательский ключевой экстрактор :

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;

См. Расширенные функции экстракторов ключей Boost.MultiIndex

5 голосов
/ 27 октября 2009

Я считаю, что вам нужно создать объект-предикат, который принимает два экземпляра Foo, и его оператор () может вызывать Foo :: bar () в обоих случаях.

Что-то вроде

struct MyPredicate
{

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

и затем используйте

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

Оформить заказ MultiIndex Заказанные индексы

1 голос
/ 27 октября 2009

Насколько мне нравится использовать лямбды для простых вещей, это может быстро выродиться:)

В вашем случае, поскольку это немного сложнее, я бы полагался либо на свободную функцию, либо на предикатный компаратор.

Преимущество предиката состоит в более четком определении типов, поэтому обычно проще его ввести.

Кроме того, для удобства чтения я обычно печатаю свои индексы, что дает:

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;

Подход с использованием предикатов требует большего количества стандартного кода, но он позволяет красиво отделить логику сравнения от определения индекса, которое само отделено от определения контейнера.

Четкое разделение облегчает обзор структуры.

...