C++ Dynamically assign std::map comparator

喜你入骨 提交于 2019-12-01 11:44:53

You can't change the comparator after the fact. But you can use the same comparator class and get either "greater" or "less" at the time of construction. You just need a stateful comparator:

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

Then you can do

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

The extra pair of parentheses is because it would otherwise be the most vexing parse , even though a function parameter declaration cannot have a qualified name. In C++11, list-initialization (my_compare{mycompare::less}) can be used instead.


For your specific design, an implementation might look like

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

No. The comparison function is used to generate the actual data structure -- changing the comparison function would require rebuilding the structure from scratch.

That said, if all you want to do is iterate the structure in reverse order, map is a reversible container, so you can just loop over the structure normally using the reverse iterators.

You can do what you want to do by creating a custom functor class that uses less or greater depending on some state. Here's an example:

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

Output:

Map 1: 
Key: 1, Value: abcd
Key: 2, Value: lmnop
Key: 3, Value: xyz
Map 2: 
Key: 3, Value: xyz
Key: 2, Value: lmnop
Key: 1, Value: abcd

In your case, you can pass a flag from the child class to the parent class indicating what value to use to create the compare functor.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!