C++で構造体型のvector変数をソートする方法

C++で構造体型の変数を使っている時、その変数の配列もしくはvectorをソートする方法を紹介します。
方法自体はいくつかあるみたいなのですが、今回は「演算子のオーバーロード」で実現したいと思います。
つまり、本来使用できない構造体の演算子(”>”や”<“)に意味を持たせて(オーバーロードして)使用できるようにします。
構造体の演算子をオーバーロードするには、operatorというメンバ関数を追加します。

struct Struct {
    int num1;
    int num2;

    bool operator<(const Struct& another) const {
        //メンバ変数であるnum1で比較した結果を
        //この構造体の比較とする
        return num1 < another.num1;
    }
};

こうすると、Struct型変数同士の比較ができるため、Struct型のままstd::sort関数に渡してソートすることができます。
(std::sort関数は、”<“のみを使ってソートしているため”<“のみの記述でソートが可能です。もし、”>”演算子を使う必要があるときは同様にoperator関数を追加してください。)

#include <iostream>
#include <vector> //for vector
#include <algorithm> //for sort

using namespace std;

struct Struct {
    int num1;
    int num2;

    Struct(int n1, int n2) {
        num1 = n1;
        num2 = n2;
    }

    bool operator<(const Struct& another) const {
        return num1 < another.num1;
    }
};

int main() {
    vector<Struct> vec;
    vec.push_back(Struct(10, 20));
    vec.push_back(Struct(5, 5));
    vec.push_back(Struct(15, 10));

    cout << "Before" << endl;
    for (int i = 0; i < vec.size(); i++) {
        cout << i << ": num1=" << vec[i].num1 << ", num2=" << vec[i].num2 << endl;
    }

    //ここでソートする
    sort(vec.begin(), vec.end());

    cout << "\nAfter" << endl;
    for (int i = 0; i < vec.size(); i++) {
        cout << i << ": num1=" << vec[i].num1 << ", num2=" << vec[i].num2 << endl;
    }

    return 0;
}

実行結果

Before
0: num1=10, num2=20
1: num1=5, num2=5
2: num1=15, num2=10

After
0: num1=5, num2=5
1: num1=10, num2=20
2: num1=15, num2=10

num1の値でソートされていることが分かります。

例2:クラスでも可能

構造体での演算子オーバーロードを紹介しましたが、クラスでも構造体と同じように演算子オーバーロードができます。
(当たり前。というか逆にクラスで演算子オーバーロードができるからC++の構造体では演算子オーバーロードができる、というのが正しい流れですね)

#include <iostream>
#include <vector> //for vector
#include <algorithm> //for sort

using namespace std;

class Class {
public:
    int num1;
    int num2;

    Class(int n1, int n2) {
        num1 = n1;
        num2 = n2;
    }

    bool operator<(const Class& another) const {
        return num1 < another.num1;
    }
};

int main() {
    vector<Class> vec;
    vec.push_back(Class(10, 20));
    vec.push_back(Class(5, 5));
    vec.push_back(Class(15, 10));

    cout << "Before" << endl;
    for (int i = 0; i < vec.size(); i++) {
        cout << i << ": num1=" << vec[i].num1 << ", num2=" << vec[i].num2 << endl;
    }

    //ここでソートする
    sort(vec.begin(), vec.end());

    cout << "\nAfter" << endl;
    for (int i = 0; i < vec.size(); i++) {
        cout << i << ": num1=" << vec[i].num1 << ", num2=" << vec[i].num2 << endl;
    }

    return 0;
}

実行結果は構造体の時と同じです。

補足

この方法は演算子の挙動を自分で変えてしまうものなので、同じプログラムを使い続けていると気づかない内に不具合を起こしてしまう、という可能性は残ってしまいます。
そのため、この方法は一時的な(または将来拡張しないことが前提の)プログラムに対する処置と割り切り、そうでない場合はpairやmapといった他のコンテナクラスを用いた設計に変える対策をとるほうが良いかもしれません。