web-dev-qa-db-ja.com

constが 'operator>'ではなく、 'operator <'に必要なのはなぜですか?

次のコードを検討してください。

#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;

struct MyStruct
{
    int key;
    std::string stringValue;

    MyStruct(int k, const std::string& s) : key(k), stringValue(s) {}

    bool operator < (const MyStruct& other) {
        return (key < other.key);
    }
};

int main() {
    std::vector < MyStruct > vec;

    vec.Push_back(MyStruct(2, "is"));
    vec.Push_back(MyStruct(1, "this"));
    vec.Push_back(MyStruct(4, "test"));
    vec.Push_back(MyStruct(3, "a"));

    std::sort(vec.begin(), vec.end());

    for (const MyStruct& a : vec) {
        cout << a.key << ": " << a.stringValue << endl;
    }
}

正常にコンパイルされ、予想される出力が得られます。しかし、降順で構造をソートしようとすると:

#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;

struct MyStruct
{
    int key;
    std::string stringValue;

    MyStruct(int k, const std::string& s) : key(k), stringValue(s) {}

    bool operator > (const MyStruct& other) {
        return (key > other.key);
    }
};


int main() {
    std::vector < MyStruct > vec;

    vec.Push_back(MyStruct(2, "is"));
    vec.Push_back(MyStruct(1, "this"));
    vec.Push_back(MyStruct(4, "test"));
    vec.Push_back(MyStruct(3, "a"));

    std::sort(vec.begin(), vec.end(), greater<MyStruct>());

    for (const MyStruct& a : vec) {
        cout << a.key << ": " << a.stringValue << endl;
    }
}

これによりエラーが発生します。 ここに完全なメッセージがあります

/usr/include/c++/7.2.0/bits/stl_function.h: 'constexpr bool std :: greater <_Tp> :: operator()(const _Tp&、const _Tp&)const [with _Tp = MyStruct]'のインスタンス化:
/usr/include/c ++/7.2.0/bits/stl_function.h:376:20:error:no match for 'operator>'(operand types are 'const MyStruct' and 'const MyStruct')
{return __x> __y; }

これは、この関数にconst修飾子がないためだと思われます。

bool operator > (const MyStruct& other) {
        return (key > other.key);
}

追加した場合、

bool operator > (const MyStruct& other) const {
        return (key > other.key);
}

その後、すべてが再び大丈夫です。これはなぜですか?私は演算子のオーバーロードにあまり詳しくないので、constを追加する必要があることをメモリに格納しましたが、operator<constなし。

56
Rockstar5645

実際には2つの異なる(オーバーロードされた) sort 関数を呼び出しているため、異なる動作になります。

最初のケースでは、_std::sort_を直接使用する2つのパラメーター_operator<_を呼び出します。ベクター要素の反復子は非const参照を生成するため、_operator<_を適切に適用できます。

2番目のケースでは、_std::sort_の3つのパラメーターバージョンを使用しています。ファンクターを受け入れるもの。 _std::greater_を渡します。そして、そのファンクターにはoperator()が次のように宣言されています:

_constexpr bool operator()( const T& lhs, const T& rhs ) const;
_

Const参照に注意してください。 const参照と比較する必要がある要素をバインドします。したがって、独自の_operator>_もconst正しい必要があります。

_std::sort_ を指定して_std::less_を呼び出すと、const-correctではないため、_operator<_は同じエラーを生成します。

83
StoryTeller

std::sort(vec.begin(), vec.end())の使用は、_operator<_関数のみに依存します。関数がconstオブジェクトを操作できる必要はありません。

一方、_std::greater_では、関数がconstオブジェクトを操作できる必要があります。

std::sort(vec.begin(), vec.end(), std::less<MyStruct>())などの_std::less_を使用すると、同様の問題が発生します。


そうは言っても、_operator<_関数と_operator>_関数が非constメンバー関数である理由はありません。メンバーデータを変更しないメンバー関数は、constメンバー関数にする必要があります。

25
R Sahu