#include <iostream>
#include <map>
#include <unordered_map>

using namespace std;

class my_int_cmp;

class MyInt {
 public:
  MyInt(int x) : x_(x) {}

  int x() const { return x_; }

  friend my_int_cmp;
  friend bool operator< (const MyInt&, const MyInt&);
 private:
  int x_;
};

bool operator< (const MyInt& lhs, const MyInt& rhs) {
  cout << "operator<: " << lhs.x_ << " < " << rhs.x_ << endl;;
  return lhs.x_ < rhs.x_;
}

class my_int_cmp {
 public:
  bool operator() (const MyInt& lhs, const MyInt& rhs) {
    cout << "my_int_cmp: " << lhs.x_ << " < " << rhs.x_ << endl;;
    return lhs.x_ < rhs.x_;
  }
};


int main(int argc, char** argv) {
  map<MyInt, string, my_int_cmp> m1; // explicitly use a comparator class
  MyInt x(9);
  MyInt y(4);

  m1[x] = "hello";
  m1[y] = "everyone";

  for (auto& p : m1) {
    cout << p.first.x() << ": " << p.second << endl;
  }

  cout << endl;

  map<MyInt, string> m2; // implicitly use operator<

  m2[x] = "hi";
  m2[y] = "people";

  for (auto& p : m2) {
    cout << p.first.x() << ": " << p.second << endl;
  }

  cout << endl;

  unordered_map<string, string> m3;

  m3["key"] = "value";
  m3["label"] = "content";

  for (auto& p : m3) {
    cout << p.first << ": " << p.second << endl;
  }

  cout << endl;

  cout << "previously non-existent key: " << m3["previously non-existent key"] << endl;

  cout << endl;

  for (auto& p : m3) {
    cout << p.first << ": " << p.second << endl;
  }

  return 0;
}