代码之家  ›  专栏  ›  技术社区  ›  piripiri

通过自定义比较不同类型的值来查找std::set的元素

  •  9
  • piripiri  · 技术社区  · 8 年前

    考虑以下玩具示例 std::set 使用自定义比较器:

    #include <set>
    
    struct A {
      A() : a(cnt++) {}
      const int a;
      static int cnt;
    };
    
    int A::cnt = 0;
    
    struct comp {
      bool operator()(const A& left, const A& right)
      {
        return left.a < right.a;
      }
    };
    
    int main()
    {
      std::set<A, comp> sa;
      for (int i = 0; i < 10; ++i) sa.insert(A());
      return 0;
    }
    

    请注意 A 不能简单地从整数创建。

    我想找一个 A. 给定值为 A::a 在里面 sa , 不构造类型为的临时对象 A. ,即我正在搜索

    sa.find(4)
    

    使用自定义比较器,允许将整数与类型为的对象进行直接比较 A. . 这可能吗?

    1 回复  |  直到 8 年前
        1
  •  15
  •   user7860670    8 年前

    使用C++14,您可以使用“透明”比较器:

    #include <iostream>
    #include <set>
    #include <type_traits>
    
    class A
    {
        public: explicit A() : a{cnt++} {}
        private: explicit A(int) = delete;
        public: const int a;
        private: static int cnt;
    };
    
    int A::cnt{};
    
    class Comparator
    {
        // this member is required to let container be aware that 
        // comparator is capable of dealing with types other than key
        public: using is_transparent = std::true_type;
    
        public: bool operator()(const int & left, const A& right) const
        {
            return left < right.a;
        }
    
        public: bool operator()(const A & left, const int& right) const
        {
            return left.a < right;
        }
    
        public: bool operator()(const A& left, const A& right) const
        {
            return left.a < right.a;
        }
    };
    
    int main()
    {
        std::set<A, Comparator> sa{};
        for (int i{}; i < 10; ++i)
        {
            sa.emplace();
        }
        std::cout << sa.find(3)->a << std::endl;
        return 0;
    }
    

    online compiler

    在C++14之前,异构查找在中可用 ::boost::intrusive::set :

    #include <boost/intrusive/set.hpp>
    #include <iostream>
    
    namespace bi = ::boost::intrusive;
    
    // hook contains set node data, supports various options, can be a member
    class A: public bi::set_base_hook
    <
        bi::link_mode<bi::link_mode_type::safe_link>
    >
    {
        public: explicit A() : a{cnt++} {}
        private: explicit A(int) = delete;
        public: const int a;
        private: static int cnt;
    };
    
    int A::cnt{};
    
    class Comparator
    {
        public: bool operator()(const int & left, const A& right) const
        {
            return left < right.a;
        }
    
        public: bool operator()(const A & left, const int& right) const
        {
            return left.a < right;
        }
    
        public: bool operator()(const A& left, const A& right) const
        {
            return left.a < right.a;
        }
    };
    
    int main()
    {
        bi::set<A, bi::compare<Comparator>> sa{Comparator{}};
        for (int i{0}; i < 10; ++i)
        {
            sa.insert(*new A{}); // typically user manages object creation
        }
        // comparators may vary
        std::cout << sa.find(3, Comparator{})->a << std::endl;
        return 0;
    }
    

    online compiler