Impulsionar o recipiente de multi-índice com índice baseado em valores aninhados
-
06-07-2019 - |
Pergunta
Se eu tiver um objeto como este:
struct Bar {
std::string const& property();
};
Eu posso criar um recipiente multi-índice para ele assim:
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;
Mas se eu tiver uma classe como este:
struct Foo {
Bar const& bar();
};
Como posso construir um índice em .bar().property()
para um recipiente de objetos Foo
?
chamadas ninho Normalmente gostaria de boost::bind
, mas eu não posso descobrir como fazê-lo funcionar no contexto de um recipiente multi-índice.
Solução
Eu acredito que você precisa para criar um objeto predicado que leva duas instâncias de Foo e seu operador () pode chamar Foo :: bar () em ambos os casos.
Algo como
struct MyPredicate
{
bool operator() (const Foo& obj1, const Foo& obj2) const
{
// fill in here
}
};
e, em seguida, usar
...
boost::multi_index::ordered_unique<boost::multi_index::tag<tag_prop>,
boost::multi_index::identity<Foo>, MyPredicate>,
...
Outras dicas
Em vez de fornecer um comparador definido pelo usuário, você pode escrever uma definida pelo usuário extractor chave :
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;
Por mais que eu gosto de usar lambdas para fazer coisas simples, isso pode rapidamente degenerar:)
No seu caso, já que é um pouco mais complicado, eu iria contar quer por uma função livre ou um comparador predicado.
O predicado tem a vantagem de definir tipos mais claramente por isso é geralmente mais fácil de realmente trazê-lo.
Além disso, por causa da legibilidade, eu geralmente typedef meus índices, o que dá:
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;
A abordagem predicado requer mais código padrão, mas permite separar muito bem a lógica de comparação do índice de definição, que é ele próprio separado da definição recipiente.
Separação clara torna mais fácil para ver a estrutura de relance.