C++で比較オブジェクト(Functor)を使用する際の注意点


くどくど言う
アルゴリズム問題を解く過程でstd::setを用いた.
初めて会う人のために簡単に説明すると….std::setは、スタンプパラメータを使用して次の事項を指定します.
  • 要素タイプ
  • 比較タイプ(比較)
  • アサイメントタイプ(アサイメント)
  • 比較タイプと割当者タイプは、要素タイプのlow-level type(int、double、...)としてdefault parameter(std::less<T>std::allocator<T>)を指定します.使用する場合は別途指定する必要はありませんが、問題は以下に示すように別定義された構造体が使用されていることです.
    struct Pos
    {
        int x;
        int y;
    }
    このように定義された座標データをxの昇順で並べ替え、xが同じであればyの昇順で並べ替えられた比較オブジェクト(Functor)をsetの比較タイプとして定義し、以下の比較オブジェクトを定義した.
    struct Compare()
    {
        bool operator()(Pos& p1, Pos& p2)
        {
            if(p1.x == p2.x)
            {
                return p1.y < p2.y;
            }
            return p1.x < p2.x;
        }
    }
    次にstd::setオブジェクトを宣言しました...
    std::set<Pos, compare> s{...};
    問題の採点中にコンパイルエラーが発生しました!
    明らかにvisualstudioは問題のないバージョンで、採点中に多くのテンプレートエラーが発生しました.スコアサーバ(Back Jun)は、コンパイラとしてg++を使用するため、Visual Studioとは異なる結果になる場合があります.
    とにかく、採点結果のエラーリストを見てみると、明らかなエラーが見えました.

    "error: static asswertion failed: comparison object must be invocable as const"
    |------- is_invocable_v
    比較オブジェクトはconstのエラーとして呼び出される必要があります.次のis_invocable_vでは、3つのスタンプパラメータがconstを受け入れることがわかります.
    いずれにしても、比較オブジェクト自体と2つのパラメータはconstとして宣言すべきであるようで、次のコードが変更されました.
    struct Compare()
    {
        bool operator()(const Pos& p1, const Pos& p2) const
        {
            if(p1.x == p2.x)
            {
                return p1.y < p2.y;
            }
            return p1.x < p2.x;
        }
    }
    修正して採点し直したら、すぐに合格!

    サマリ
  • C++で比較オブジェクトを使用する場合、条件に従ってconstを宣言しないとエラーが発生する可能性があります.
  • 比較オブジェクト
  • でなくても、関数の値を変更する必要がない場合はconstを使用する習慣を身につけなければなりません.
  • タンプルのエラーが発生しても、元気を出して、エラーメッセージを見れば解決できます(多分...)