У меня есть такой класс (упрощенный пример):
class A {
public:
typedef boost::shared_ptr<A> Ptr;
const std::string& getID() const;
const std::string& getLabel() const;
bool getFlag() const;
float getValue() const;
private:
...
};
Мне нужен контейнер, который индексируется уникальной комбинацией (id, label)
, а также уникальной комбинацией (label, flag, value)
. Мне также нужно, чтобы он был отсортирован по второму индексу по метке, за которой следует флаг, за которым следуют уменьшающиеся значения, если флаг истинен, и увеличивающиеся значения, если флаг неверен. Итак, после создания экстракторов ключей я делаю что-то вроде этого:
typedef boost::multi_index::composite_key<
Ptr, extractor_id, extractor_label
> id_label_key;
typedef boost::multi_index::composite_key<
Ptr, extractor_label, extractor_flag, extractor_value
> label_flag_value_key;
...
typedef boost::multi_index_container<Ptr,
boost::multi_index::indexed_by<
boost::multi_index::ordered_unique<
boost::multi_index::tag<by_id_label
id_label_key
>,
boost::multi_index::ordered_unique<
boost::multi_index::tag<by_label_flag_value>,
label_flag_value_key,
Compare
>,
>
> Items;
typedef Items::index<by_label_flag_value>::type Items_by_label_flag_value;
где Сравнить определяется как:
struct Compare {
bool operator() (const boost::multi_index::composite_key_result<label_flag_value_key>& k, const boost::tuple<float,bool>& q) const {
return compare(k.value->getLabel(), k.value->getFlag(), k.value->getValue(),
q.get<0>(), q.get<1>(), q.get<2>()
}
bool operator() (const boost::tuple<float,bool>& q, const boost::multi_index::composite_key_result<label_flag_value_key>& k) const {
return compare(q.get<0>(), q.get<1>(), q.get<2>(),
k.value->getLabel(), k.value->getFlag(), k.value->getValue(),
}
bool operator() (const boost::multi_index::composite_key_result<label_flag_value_key>& k1, const boost::multi_index::composite_key_result<label_flag_value_key>& k2) const {
return compare(k1.value->getLabel(), k1.value->getFlag(), k1.value->getValue(),
k2.value->getLabel(), k2.value->getFlag(), k2.value->getValue())
}
bool compare(const std::string& l1, bool f1, float v1, const std::string& l2, bool f2, float v2) const {
if (l1 != l2) return l1 < l2;
if (f1 != f2) return f1;
return f1 ? (v1 > v2) : (v1 < v2);
}
};
Теперь я могу выполнять такие запросы:
Items_by_label_flag_value::const_iterator it = items_by_label_flag_value.find(boost::make_tuple("A", true, 0.1));
Однако, если я попытаюсь выполнить частичный запрос, например, получить все элементы с одинаковыми метками, мой код не скомпилируется:
std::pair<Items_by_label_flag_value::const_iterator, Items_by_label_flag_value::const_iterator> range = items_by_label_flag_value.equal_range(boost::make_tuple("A"));
Я знаю, почему он не компилируется: в компараторе я явно использую .get<0>()
, .get<1>()
и .get<2>()
, но кортеж частичного поиска не имеет элементов <1>
и <2>
. Чего я не знаю, так это как создать правильный компаратор. Если я попытаюсь добавить к нему еще две функции, которые принимают кортежи только из одного элемента, то компилятор жалуется на неоднозначность в вызове operator()
.
Я также понимаю, что composite_key_result
должен быть непрозрачным объектом, и мне не следует использовать его внутренности.
Итак, мой вопрос: как создать нужный индекс и правильный компаратор?