C++ Динамически назначать компилятор std::map

Таким образом, у меня есть два класса, содержащие члены std:: map с фактически идентичной функциональностью, за исключением того, что порядок одной карты - std:: less, а другого std:: more.

Если я создаю абстрактный родительский класс и объявляю один член карты, есть ли способ динамически назначить компаратор для этого члена в конструкторах производного класса? Таким образом, функциональность, очевидно, может находиться в родительском классе.

3 ответа

Решение

Вы не можете изменить компаратор после факта. Но вы можете использовать один и тот же класс компаратора и получить "больше" или "меньше" во время построения. Вам просто нужен компаратор с состоянием:

struct my_compare {
    enum compare_type { less, greater };
    explicit my_compare(compare_type t) : m_type(t) {}
    template<class T, class U>
    bool operator()(const T& t, const U& u) const {
        if(m_type == less) { return t < u; }
        else { return t > u; }
    }
    compare_type m_type;
};

Тогда вы можете сделать

std::map<int, int, my_compare> less_map((my_compare(my_compare::less)));
std::map<int, int, my_compare> greater_map((my_compare(my_compare::greater)));

Дополнительная пара скобок объясняется тем, что в противном случае это был бы самый неприятный анализ, даже если объявление параметра функции не может иметь квалифицированного имени. В C++11, инициализация списка (my_compare{mycompare::less}) можно использовать вместо.


Для вашего конкретного проекта реализация может выглядеть так

class A {
protected:
    explicit A(my_compare::compare_type ct) : my_map(my_compare(ct)) {}
    std::map<int, int, my_compare> my_map;
};

class B_less : public A{
public:
    B_less() : A(my_compare::less) {}
};

Вы можете делать то, что хотите, создав собственный класс функторов, который использует меньше или больше, в зависимости от состояния. Вот пример:

#include <iostream>
#include <string>
#include <map>

struct MyCompare
{
   MyCompare(bool useLess) : useLess_(useLess) {}

   bool operator()(int lhs, int rhs)
   {
      if ( useLess_ )
      {
         return (lhs < rhs);
      }
      else
      {
         return (lhs > rhs);
      }
   }
   bool useLess_;
};

int main(int argc, char** argv)
{
   std::map<int, std::string, MyCompare> myMap1(MyCompare(true));
   std::map<int, std::string, MyCompare> myMap2(MyCompare(false));

   myMap1[1] = "abcd";
   myMap1[2] = "lmnop";
   myMap1[3] = "xyz";

   myMap2[1] = "abcd";
   myMap2[2] = "lmnop";
   myMap2[3] = "xyz";

   std::cout << "Map 1: " << std::endl; for ( auto const& v : myMap1 )
   {
      std::cout << "Key: " << v.first << ", Value: " << v.second << std::endl;
   }

   std::cout << "Map 2: " << std::endl;
   for ( auto const& v : myMap2 )
   {
      std::cout << "Key: " << v.first << ", Value: " << v.second << std::endl;
   }

   return 0;
}

Выход:

Карта 1: 
Ключ: 1, значение: abcd
Ключ: 2, значение: lmnop
Ключ: 3, Значение: XYZ
Карта 2: 
Ключ: 3, Значение: XYZ
Ключ: 2, значение: lmnop
Ключ: 1, значение: abcd

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

Нет. Функция сравнения используется для генерации фактической структуры данных - изменение функции сравнения потребует перестройки структуры с нуля.

Тем не менее, если все, что вы хотите сделать, это перебрать структуру в обратном порядке, map является обратимым контейнером, так что вы можете просто перебрать структуру, используя обратные итераторы.

Другие вопросы по тегам