C++ Dynamically assign std::map comparator

前端 未结 3 655
傲寒
傲寒 2021-01-16 09:40

So I have two classes containing std::map members with effectively identical functionality except that the ordering of one map is std::less and the other std::greater.

相关标签:
3条回答
  • 2021-01-16 10:08

    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) {}
    };
    
    0 讨论(0)
  • 2021-01-16 10:18

    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.

    0 讨论(0)
  • 2021-01-16 10:27

    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.

    0 讨论(0)
提交回复
热议问题