Home > database >  Problem using boost::multi_index with composite key member functions
Problem using boost::multi_index with composite key member functions

Time:10-29

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 :(

CodePudding user response:

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>
  • Related