Увеличить многоиндексный пользовательский составной ключ сравнения - PullRequest
4 голосов
/ 25 августа 2009

Я ищу написать собственный компаратор для индекса повышения ordered_non_unique с составным ключом. Я не совсем уверен, как это сделать. Boost имеет composite_key_comparer, но это не сработает для меня, потому что один из сравнителей для члена ключа зависит от предыдущего члена. Это упрощенный пример, но я хочу, чтобы индекс сортировался по убыванию по third_, когда second_ равен 'A', сохраняя сначала значения 0 для third_ и используя std :: less во всех других случаях. Надеюсь, это имеет смысл. Я хотел бы распечатать приведенный ниже код:

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;
}

1 Ответ

4 голосов
/ 22 сентября 2009

Я думаю, что вы врезались в стену.

Вы можете обратиться сюда: Упорядоченные индексы

Как и в случае с 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. Если вы собираетесь использовать этот способ сортировки более одного раза, вам, вероятно, следует предпочесть это решение. Однако, если ваш контейнер будет единственным, который будет его использовать, то лучше использовать пользовательский предикат. </p>

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...