Увеличить многоиндексный контейнер с индексом, основанным на вложенных значениях
-
06-07-2019 - |
Вопрос
Если у меня есть такой объект:
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
, но не могу понять, как заставить его работать в контексте многоиндексного контейнера.
Решение
Я считаю, что вам нужно создать объект-предикат, который принимает два экземпляра 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 а> р>
Другие советы
Вместо того, чтобы предоставлять пользовательский компаратор, вы можете написать пользовательский ключевой экстрактор :
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 р>
Насколько мне нравится использовать лямбды для простых вещей, это может быстро выродиться:)
В вашем случае, поскольку это немного сложнее, я бы полагался либо на свободную функцию, либо на предикатный компаратор.
Преимущество предиката состоит в более четком определении типов, поэтому обычно его проще ввести.
Кроме того, для удобства чтения я обычно печатаю свои индексы, что дает:
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;
Подход с использованием предикатов требует большего количества стандартного кода, но он позволяет красиво отделить логику сравнения от определения индекса, которое само по себе отделено от определения контейнера.
Четкое разделение облегчает обзор структуры.