2009-08-24 5 views
3

Я ищу, чтобы написать пользовательский сопоставитель для повышения индекса ordered_non_unique с составным ключом. Я не совсем уверен, как это сделать. Boost имеет composite_key_comparer, но это не сработает для меня, потому что один из сопоставлений для члена ключа зависит от предыдущего участника. Это упрощенный пример, но я хочу, чтобы индекс сортировался по убыванию на third_, когда second_ является «А», сохраняя 0 значений для third_, и используйте std :: less во всех остальных случаях. Надеюсь, это имеет смысл. Я хотел бы код, приведенный ниже, чтобы распечатать:Boost Multi-Index Custom Composite Key Comparer

3,BLAH,A,0 
5,BLAH,A,11 
2,BLAH,A,10 
4,BLAH,A,9 
1,BLAH,A,8 

Код бы вместо ЧТО ЗДЕСЬ ???. Спасибо за любую помощь.

#include <boost/multi_index_container.hpp> 
#include <boost/multi_index/key_extractors.hpp> 
#include <boost/multi_index/ordered_index.hpp> 
#include <boost/multi_index/composite_key.hpp> 
#include <iostream> 

namespace bmi = boost::multi_index; 
namespace bt = boost::tuples; 

struct Widget 
{ 
    Widget (const std::string& id, const std::string& f, char s, unsigned int t) 
    : id_(id) 
    , first_(f) 
    , second_(s) 
    , third_(t) 
    { } 

    ~Widget() { } 

    std::string id_; 
    std::string first_; 
    char second_; 
    unsigned int third_; 
}; 

std::ostream& operator<< (std::ostream& os, const Widget& w) 
{ 
    os << w.id_ << "," << w.first_ << "," << w.second_ << "," << w.third_; 
    return os; 
} 

struct id_index { }; 
struct other_index { }; 

typedef bmi::composite_key< 
    Widget*, 
    bmi::member<Widget, std::string, &Widget::first_>, 
    bmi::member<Widget, char, &Widget::second_>, 
    bmi::member<Widget, unsigned int, &Widget::third_> 
> other_key; 

typedef bmi::multi_index_container< 
    Widget*, 
    bmi::indexed_by< 
    bmi::ordered_unique< 
     bmi::tag<id_index>, 
     bmi::member<Widget, std::string, &Widget::id_> 
    >, 
    bmi::ordered_non_unique< 
     bmi::tag<other_index>, 
     other_key, 
     ***************WHAT GOES HERE???*************** 
    > 
    > 
> widget_set; 

typedef widget_set::index<other_index>::type widgets_by_other; 
typedef widgets_by_other::iterator other_index_itr; 

int main() 
{ 
    widget_set widgets; 
    widgets_by_other& wbo_index = widgets.get<other_index>(); 
    Widget* w; 

    w = new Widget("1", "BLAH", 'A', 8); 
    widgets.insert(w); 
    w = new Widget("2", "BLAH", 'A', 10); 
    widgets.insert(w); 
    w = new Widget("3", "BLAH", 'A', 0); 
    widgets.insert(w); 
    w = new Widget("4", "BLAH", 'A', 9); 
    widgets.insert(w); 
    w = new Widget("5", "BLAH", 'A', 11); 
    widgets.insert(w); 

    std::pair<other_index_itr,other_index_itr> range = 
    wbo_index.equal_range(boost::make_tuple("BLAH", 'A')); 

    while (range.first != range.second) 
    { 
    std::cout << *(*range.first) << std::endl; 
    ++range.first; 
    } 

    return 0; 
} 

ответ

3

Я думаю, вы попали в стену.

Вы можете обратиться сюда: Ordered Indices

Как с STL, вы на самом деле должны предоставить критерии сравнения себя, и, таким образом, вы будете иметь возможность адаптировать его к вашим потребностям.

Как объяснено на странице я связан (в разделе «предикатов сравнения»):

В последней части спецификации упорядоченного индекса является ассоциированной сравнение предикатом, который должен заказать ключи в менее Это мода.

Таким образом, ваша работа два раза:

  1. Вам нужно определить подходящее сравнение предикат, который работает на ваших типов
  2. Вы должны указать Boost.MultiIndex, что вы хотите используйте этот предикат для фактического сопоставления ключей.
struct WidgetComparer 
{ 
    bool operator()(const Widget& lhs, const Widget& rhs) const 
    { 
    if (lhs._second == 'A' && rhs._second == 'A') 
    { 
     return lhs._third == 0 || rhs._third < lhs._third; 
    } 
    else 
    { 
     return lhs._third < rhs._third; 
    } 
    } // operator() 
}; 

И тогда вам просто нужно заполнить свой индекс. Поэтому замените «другой ключ» на . < Виджет> и «ЧТО ИМЕЕТСЯ ЗДЕСЬ» с WidgetComparer.

И вот вы идете!

Важным моментом является то, что вы не должны фокусироваться на «ключевой» части контейнера. Ключ ничего сам по себе, это пара (ключ, предикат сравнения), который выполняет фактический порядок. Основное внимание уделяется ключам в документации для улучшения повторного использования кода (и, в частности, для использования предикатов сравнения, которые уже реализованы как std :: less).

В качестве альтернативы вы могли бы запрограммировать «оператор <» для вашего класса Widget или специализировать алгоритм std :: less. Если вы собираетесь использовать этот способ сортировки более одного раза, вы, вероятно, предпочтете это решение. Однако, если ваш контейнер является единственным, который будет его использовать, тогда пользовательский предикат лучше.

Надеюсь, что помогло.