次のコードを検討してください。
#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
なし。
実際には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<
_は同じエラーを生成します。
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
メンバー関数にする必要があります。