1. ホーム
  2. c++

[解決済み] カスタムstd::setコンパレータを使用する

2022-04-25 02:16:15

質問

整数の集合の項目のデフォルトの順序を、数値ではなく辞書式に変更しようとしているのですが、g++で次のようにコンパイルすることができません。

ファイル.cppを作成します。

bool lex_compare(const int64_t &a, const int64_t &b) 
{
    stringstream s1,s2;
    s1 << a;
    s2 << b;
    return s1.str() < s2.str();
}

void foo()
{
    set<int64_t, lex_compare> s;
    s.insert(1);
    ...
}

以下のようなエラーが発生します。

error: type/value mismatch at argument 2 in template parameter list for ‘template<class _Key, class _Compare, class _Alloc> class std::set’
error:   expected a type, got ‘lex_compare’

私は何を間違えているのでしょうか?

どうすればいいですか?

1. モダンC++20ソリューション

auto cmp = [](int a, int b) { return ... };
std::set<int, decltype(cmp)> s;

を使用します。 ラムダ関数 をコンパレータとして使用します。通常、コンパレータはブール値を返す必要があり、これは最初の引数として渡された要素が、具体的には次の引数の前に行くものと見なされるかどうかを示します。 厳密な弱い順序 が定義されています。

オンラインデモ

2. モダンC++11ソリューション

auto cmp = [](int a, int b) { return ... };
std::set<int, decltype(cmp)> s(cmp);

C++20以前では、コンストラクタを設定する際にラムダを引数として渡す必要がありました。

オンラインデモ

3. 最初の解決策と似ていますが、ラムダの代わりに関数を使用しています。

コンパレータを通常のブール関数にする

bool cmp(int a, int b) {
    return ...;
}

そして、このどちらかの方法で、使ってください。

std::set<int, decltype(cmp)*> s(cmp);

オンラインデモ

またはこのように

std::set<int, decltype(&cmp)> s(&cmp);

オンラインデモ

4.構造体を使った古い解決策 () オペレータ

struct cmp {
    bool operator() (int a, int b) const {
        return ...
    }
};

// ...
// later
std::set<int, cmp> s;

オンラインデモ

5. 代替案:ブーリアン関数から構造体を作成する。

ブーリアン関数を取る

bool cmp(int a, int b) {
    return ...;
}

そして、それを使って構造体を作る std::integral_constant

#include <type_traits>
using Cmp = std::integral_constant<decltype(&cmp), &cmp>;

最後に、構造体をコンパレータとして使用します。

std::set<X, Cmp> set;

オンラインデモ