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
является обратимым контейнером, так что вы можете просто перебрать структуру, используя обратные итераторы.