Шаг 169.
Библиотека STL. Контейнеры STL. Операции над множествами и мультимножествами. Определение критерия сортировки на стадии выполнения

    На этом шаге мы рассмотрим способ задания критерия сортировки во время выполнения программы.

    Обычно критерий сортировки определяется как часть типа; для этого он либо явно передается во втором аргументе шаблона, либо по умолчанию используется критерий less<>. Но иногда критерий сортировки приходится определять во время выполнения программы или для одного типа данных определяются разные критерии сортировки. В таких случаях для критерия сортировки определяется специальный тип, в котором передается информация о сортировке. Следующая программа показывает, как это делается.

//---------------------------------------------------------------------------

#include <vcl.h>
#include <iostream>
#include <iterator>
#include <set>
#include <conio.h> //необходимо для getch()

#pragma hdrstop

//---------------------------------------------------------------------------

#pragma argsused
using namespace std;

std::string ToRus(const std::string &in)
{
  char *buff = new char [in.length()+1];
  CharToOem(in.c_str(),buff);
  std::string out(buff);
  delete [] buff;
  return out;
}

template <class T>
inline void PRINT_ELEMENTS (const T& coll, const char* optcstr="")
{
  typename T::const_iterator pos;
  std::cout << ToRus(optcstr);
  for (pos=coll.begin(); pos!=coll.end(); ++pos) {
    std::cout <<*pos <<' ';
  }
  std::cout << std::endl;
}

// Тип критерия сортировки 
template <class T>
class RuntimeCmp {
  public: 
    enum cmp_mode {normal, reverse};
  private: 
    cmp_mode mode;
  public:
    // Конструктор критерия сортировки 
    // - по умолчанию используется значение normal 
    RuntimeCmp (cmp_mode m=normal) : mode(m) { }

    // Сравнение элементов
    bool operator() (const T& t1, const T& t2) const { 
      return mode == normal ? t1 < t2 : t2 < t1;
    }

    // Сравнение критериев сортировки 
    bool operator== (const RuntimeCmp& rc) { 
      return mode = rc.mode;
    }
};

// Тип множества, использующего данный критерий сортировки 
typedef set<int,RuntimeCmp<int> > IntSet;

// Опережающее объявление 
void fill (IntSet& set);


int main(int argc, char* argv[])
{
  // Создание, заполнение и вывод множества с обычным порядком следования
  // элементов - используется критерий сортировки по умолчанию
  IntSet coll1;
  fill(coll1);
  PRINT_ELEMENTS (coll1, "coll1: ");

  // Создание критерия сортировки с обратным порядком следования элементов
  RuntimeCmp<int> reverse_order(RuntimeCmp<int>::reverse);

  // Создание, заполнение и вывод множества
  // с обратным порядком следования элементов
  IntSet coll2(reverse_order);
  fill(coll2);
  PRINT_ELEMENTS (coll2, "coll2: ");

  // Присваивание элементов и критерия сортировки
  coll1 = coll2;
  coll1.insert(3);
  PRINT_ELEMENTS (coll1, "coll1: ");
 
  // Просто для уверенности...
  if (coll1.value_comp() == coll2.value_comp()) {
    cout << ToRus("coll1 и coll2 имеют одинаковый критерий сортировки") << endl;
  }
  else {
    cout << ToRus("coll1 и coll2 имеют разный критерий сортировки") << endl;
  }

  getch();
  return 0;
}

void fill (IntSet& set)
{
  // Вставка элементов в произвольном порядке
  set.insert(4);
  set.insert(7);
  set.insert(5);
  set.insert(1);
  set.insert(6);
  set.insert(2);
  set.insert(5);
}
//---------------------------------------------------------------------------
Текст этого примера можно взять здесь.

    В этой программе RuntimeCmp<> представляет собой простой шаблон, позволяющий задать критерий сортировки для произвольного типа во время выполнения программы. Конструктор по умолчанию сортирует элементы по возрастанию, для чего используется стандартное значение normal. Также при вызове конструктора может быть передан аргумент RuntimeCmp<>::reverse, чтобы сортировка осуществлялась по убыванию.

    Результат выполнения программы выглядит так:


Рис.1. Результат выполнения приложения

    Контейнеры coll1 и соll2 относятся к одному типу, и это обстоятельство используется, например, в функции fill(). Также обратите внимание на то, что оператор присваивания присваивает элементы и критерий сортировки (иначе присваивание легко приводило бы к нарушению упорядоченности).

    Со следующего шага мы начнем знакомиться с отображениями и мультиотображениями.




Предыдущий шаг Содержание Следующий шаг