有一个自定义的 class A:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
class A {
public:
  A() {}
  ~A() {}

  int getVal() const { return val; }
  void setVal(int i) { val = i; }

private:
  int val;
};

当尝试把 class A 的对象存到 std::set 或作为key用在 std:map 中时,会有编译错误。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
#include <map>
#include <set>
using namespace std;

int main() {
  A a1, a2;

  a1.setVal(100);
  a2.setVal(-200);

  map<A, string> mapOfA;
  mapOfA[a1] = "hello";
  mapOfA[a2] = "world";

  set<A> setOfA;
  setOfA.insert(a1);
  setOfA.insert(a2);

  return 0;
}

compile error:

1
2
3
4
5
6
/usr/include/c++/9/bits/stl_function.h: In instantiation of ‘constexpr bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = A]’:
/usr/include/c++/9/bits/stl_map.h:497:32:   required from ‘std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const key_type&) [with _Key = A; _Tp = std::__cxx11::basic_string<char>; _Compare = std::less<A>; _Alloc = std::allocator<std::pair<const A, std::__cxx11::basic_string<char> > >; std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type = std::__cxx11::basic_string<char>; std::map<_Key, _Tp, _Compare, _Alloc>::key_type = A]/home/rduis/Workspace/github/notesnotes/swift/src/custom-class-in-std-map.cpp:25:12:   required from here
/usr/include/c++/9/bits/stl_function.h:386:20: error: no match for ‘operator<’ (operand types are ‘const A’ and ‘const A’)
  386 |       { return __x < __y; }
      |                ~~~~^~~~~

solution 1:

declare operator < in class A:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
class A {
public:
  A() {}
  ~A() {}

  int getVal() const { return val; }
  void setVal(int i) { val = i; }

  // solution 1: operator <
  bool operator<(const A &rhs) const { return val < rhs.getVal(); }

private:
  int val;
};

solution 2:

  1. create a new class as comparator
  2. modify map declaration:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
class A {
public:
  A() {}
  ~A() {}

  int getVal() const { return val; }
  void setVal(int i) { val = i; }

private:
  int val;
};

// solution 2: delcare comparator
class comparator
{
    public:
    bool operator()(const A& lhs, const A& rhs) const {
        return lhs.getVal() < rhs.getVal();
    }
};

Why

  • std::map and std::set are sorted associative containers.

  • Sorting is done using the comparison function Compare.

  • Declaration of std::map:

    1
    2
    3
    4
    5
    6
    
    template<
        class Key,
        class T,
        class Compare = std::less<Key>,
        class Allocator = std::allocator<std::pair<const Key, T>>
    > class map;
    
  • Declaration of std::map:

    1
    2
    3
    4
    5
    
    template<
      class Key,
      class Compare = std::less<Key>,
      class Allocator = std::allocator<Key>
    > class set;
    

Ref