---
id: custom-cpp-stl
title: "C++ Sets with Custom Comparators"
author: Siyong Huang, Benjamin Qi
prerequisites: 
 - sorting-custom
 - intro-ordered
description: "?"
frequency: 1
---

<resources>
  <resource source="fushar" title="Comparison Functions in C++" starred url="http://fusharblog.com/3-ways-to-define-comparison-functions-in-cpp/">Covers all of this material.</resource>
</resources>

<br />

What if we want to use a C++ `set` with the `Edge` struct that was defined in "Sorting with Custom Comparators"?

## Operator Overloading

Works as expected, although you should make sure to include the second `const` or you'll get a compilation error. From the link above:

> [The second const] means you cannot modify member variables of the current object.

```cpp
#include <bits/stdc++.h>
using namespace std;

struct Edge {
    int a,b,w;
    bool operator<(const Edge& y) const { return w < y.w; }
};

int main() {
    int M = 4;
    set<Edge> v;
    for (int i = 0; i < M; ++i) {
        int a,b,w; cin >> a >> b >> w;
        v.insert({a,b,w});
    }
    for (Edge e: v) cout << e.a << " " << e.b << " " << e.w << "\n";
}
```


## Comparator

```cpp
#include <bits/stdc++.h>
using namespace std;

struct Edge {
    int a,b,w;
};

bool cmp(const Edge& x, const Edge& y) { return x.w < y.w; }

int main() {
    int M = 4;
    set<Edge,bool(*)(const Edge&,const Edge&)> v(cmp);
    for (int i = 0; i < M; ++i) {
        int a,b,w; cin >> a >> b >> w;
        v.insert({a,b,w});
    }
    for (Edge e: v) cout << e.a << " " << e.b << " " << e.w << "\n";
}
```

Lambda expressions also work:

```cpp
auto cmp = [](const Edge& x, const Edge& y) { return x.w < y.w; };

int main() {
    int M = 4;
    set<Edge,bool(*)(const Edge&,const Edge&)> v(cmp);
    for (int i = 0; i < M; ++i) {
        int a,b,w; cin >> a >> b >> w;
        v.insert({a,b,w});
    }
    for (Edge e: v) cout << e.a << " " << e.b << " " << e.w << "\n";
}
```

In this case, we can shorten the declaration of `v` by writing `set<Edge,decltype(cmp)> v(cmp);` instead.

## Functors

Probably less confusing than the method above.

```cpp
#include <bits/stdc++.h>
using namespace std;

struct Edge {
    int a,b,w;
};

struct cmp {
    bool operator()(const Edge& x, const Edge& y) { return x.w < y.w; }
};

int main() {
    int M = 4;
    set<Edge,cmp> v;
    for (int i = 0; i < M; ++i) {
        int a,b,w; cin >> a >> b >> w;
        v.insert({a,b,w});
    }
    for (Edge e: v) cout << e.a << " " << e.b << " " << e.w << "\n";
}
```

We can also use `cmp` like a normal function by adding `()` after it.

```cpp
int main() {
    int M = 4;
    vector<Edge> v;
    for (int i = 0; i < M; ++i) {
        int a,b,w; cin >> a >> b >> w;
        v.push_back({a,b,w});
    }
    sort(begin(v),end(v),cmp());
    for (Edge e: v) cout << e.a << " " << e.b << " " << e.w << "\n";
}
```

## Built-In Functors

Overloading the less than operator (`<`) automatically generates the functor `less<Edge>`. Similarly, overloading `>` automatically generates the functor [`greater<Edge>`](https://en.cppreference.com/w/cpp/utility/functional/greater). We can use this to store a set in reverse order.

```cpp
#include <bits/stdc++.h>
using namespace std;

struct Edge {
    int a,b,w;
    bool operator>(const Edge& y) const { return w > y.w; }
};

int main() {
    int M = 4;
    set<Edge,greater<Edge>> v;
    for (int i = 0; i < M; ++i) {
        int a,b,w; cin >> a >> b >> w;
        v.insert({a,b,w});
    }
    for (Edge e: v) cout << e.a << " " << e.b << " " << e.w << "\n";
}

/* Output:
2 3 10
1 2 9
1 3 7
2 4 3
*/
```

## Other Containers

The following are all valid:

```cpp
set<int,greater<int>> a;
map<int,string,greater<int>> b;
priority_queue<int,vector<int>,greater<int>> c;
```