【问题标题】:C++ Dynamically assign std::map comparatorC++ 动态分配 std::map 比较器
【发布时间】:2015-05-11 09:05:32
【问题描述】:

所以我有两个包含 std::map 成员的类,它们具有实际上相同的功能,除了一个映射的顺序是 std::less 和另一个 std::greater。

如果我创建一个抽象父类并声明一个映射成员,有没有办法在派生类构造函数中为该成员动态分配比较器?这样,功能显然可以全部驻留在父类中。

【问题讨论】:

    标签: c++ c++11 dynamic comparator stdmap


    【解决方案1】:

    事后您无法更改比较器。但是您可以使用相同的比较器类并在构建时获得“更大”或“更少”。你只需要一个有状态的比较器:

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

    额外的一对括号是因为it would otherwise be the most vexing parse , even though a function parameter declaration cannot have a qualified name。在 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) {}
    };
    

    【讨论】:

    • 我尝试了以下但得到一个语义错误“初始化key_compare没有匹配的构造函数”class A { public: A() {} void DoSomethingWithMyMap() {}; protected: std::map&lt;int, int, my_compare&gt; my_map; }; class B_less: public A { public: B_less () { my_map = std::map&lt;int, int, my_compare&gt; (my_compare(my_compare::less)); } }; class B_greater : public A { public: B_greater () { my_map = std::map&lt;int, int, my_compare&gt; (my_compare(my_compare::greater)); } }; int main(int argc, const char * argv[]) { return EXIT_SUCCESS; }
    • 初始化需要在A的构造函数的成员初始化列表中完成(所以你需要给A一个构造函数,它接受my_compare::compare_type并拥有B的构造函数调用该构造函数);或者,您可以给my_compare 的构造函数一个默认参数,但这样效率较低。
    • 太棒了。感谢您的帮助!
    【解决方案2】:

    没有。比较函数用于生成实际的数据结构——更改比较函数需要从头开始重建结构。

    也就是说,如果您只想以相反的顺序迭代结构,map 是一个可逆容器,因此您可以使用反向迭代器正常循环结构。

    【讨论】:

    • 感谢比利的快速回复。在这种情况下,我不需要迭代结构,除了直接键访问和插入之外,我只想能够访问地图的顶部元素。不过我喜欢这个主意。这将如何动态实现,以便函数本身都可以在基类中定义(只是重新定义构造函数)?当我在基类中声明它时,我是否也必须定义 std::iterator 的类型?如果不是,并且我在一个派生类中将其重新定义为 std::reverse_iterator> ,我该如何像在另一个派生类中一样对其进行改进?
    • 另外,关于您对更改比较功能需要从头开始重建结构的评论,那可能吗?因为我的父类是抽象的,并且无论何时构造派生类之一,它们的映射结构无论如何都会严格为空。
    【解决方案3】:

    您可以通过创建一个自定义仿函数类来做您想做的事情,该类根据某些状态使用更少或更多。这是一个例子:

    #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

    在您的情况下,您可以将一个标志从子类传递给父类,指示用于创建比较函子的值。

    【讨论】:

      猜你喜欢
      • 2017-12-26
      • 1970-01-01
      • 2017-07-28
      • 1970-01-01
      • 2013-01-05
      • 2012-05-27
      • 2010-11-06
      • 2022-01-13
      • 1970-01-01
      相关资源
      最近更新 更多