I have the following container:
using KeyValue = mutable_pair<Key, Value>;
using MyContainer = boost::multi_index_container<
KeyValue,
boost::multi_index::indexed_by<
boost::multi_index::hashed_unique<
boost::multi_index::tag<KeyValueTag>,
boost::multi_index::composite_key<
KeyValue,
boost::multi_index::const_mem_fun<KeyValue::first_type, unsigned int, &KeyValue::first_type::foo>,
boost::multi_index::const_mem_fun<KeyValue::first_type, unsigned int, &KeyValue::first_type::bar>,
boost::multi_index::const_mem_fun<KeyValue::first_type, unsigned int, &KeyValue::first_type::baz>,
>
>,
boost::multi_index::hashed_non_unique<
boost::multi_index::tag<BazTag>,
boost::multi_index::const_mem_fun<KeyValue::first_type, unsigned int, &KeyValue::first_type::baz>
>,
boost::multi_index::hashed_non_unique<
boost::multi_index::tag<BarTag>,
boost::multi_index::const_mem_fun<KeyValue::first_type, unsigned int, &KeyValue::first_type::bar>
>
>
>;
Where mutable_pair
is the boost provided example for maps, and Key
is a class that contains const
member accessors for foo
, bar
and baz
.
The code compiles fine, however when trying to query by any index ie:
MyContainer c;
const auto& byBaz = c.get<BazTag>();
const auto it = byBaz.find(11);
// or
const auto [beg, end] = byBaz.equal_range(11);
it complains of
<long instantiation template error>
in mem_fun.hpp:58:23: error: no match for ‘operator*’ (operand type is ‘const mutable_pair<Key, Value>’)
58 | return operator()(*x);
What am I missing? I've been struggling with this for hours :(
The code compiles fine
That's because templates members aren't instantiated unless you use them. You don't have valid indexes for your element type.
Your indexes are trying the equivalent of
KeyValue pair;
unsigned Key::(*pfoo)() = &Key::foo;
pair.*pfoo
Instead of
pair.first.*pfoo;
You need accessors for KeyValue
, not Key
unsigned int getFoo(const KeyValue & pair) {
return pair.first.foo();
}
unsigned int getBar(const KeyValue & pair) {
return pair.first.bar();
}
unsigned int getBaz(const KeyValue & pair) {
return pair.first.baz();
}
using MyContainer = boost::multi_index_container<
KeyValue,
boost::multi_index::indexed_by<
boost::multi_index::hashed_unique<
boost::multi_index::tag<KeyValueTag>,
boost::multi_index::composite_key<
KeyValue,
boost::multi_index::global_fun<KeyValue, unsigned int, &getFoo>,
boost::multi_index::global_fun<KeyValue, unsigned int, &getBar>,
boost::multi_index::global_fun<KeyValue, unsigned int, &getBaz>,
>
>,
boost::multi_index::hashed_non_unique<
boost::multi_index::tag<BazTag>,
boost::multi_index::global_fun<KeyValue, unsigned int, &getBaz>
>,
boost::multi_index::hashed_non_unique<
boost::multi_index::tag<BarTag>,
boost::multi_index::global_fun<KeyValue, unsigned int, &getBar>
>
>
>;
Aside: If you have C++17 and boost 1.69 or later, you can use a much terser syntax for keys:
boost::multi_index::key<&getFoo, &getBar, &getBaz>
boost::multi_index::key<&getBar>