某些容器初始化时,由于std::less、std::greater仅对内置类型进行了定义,未定义自定义类型,故自定义类型需要重载std::less和std::greater。
以less函数为例,vs源码如下
template <class _Ty = void>
struct less {
_CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef _Ty _FIRST_ARGUMENT_TYPE_NAME;
_CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef _Ty _SECOND_ARGUMENT_TYPE_NAME;
_CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef bool _RESULT_TYPE_NAME;
_NODISCARD constexpr bool operator()(const _Ty& _Left, const _Ty& _Right) const {
return _Left < _Right;
}
};
std::less和std::greater判断机制:严格弱序化
严格弱序的三条要求
1.两个关键字不能同时“严格弱序”于对方
2.如果a“严格弱序”于b,且b“严格弱序”于c,则a必须“严格弱序”于c
3.如果存在两个关键字,任何一个都不“严格弱序”于另一个,则这两个关键字是相等的。
简单叙述其流程,首先左右操作数传入函数判断,然后将左右操作数交换位置,再次执行函数。如果两次结果不同,则为正常判断;如果两次都为false则认为是相等,如果两次都为true则会发生不可描述的事情(报错invalid comparator)。
在下面重载运算符时留了个破绽,可以看到其内部机制判断效果。
可以使用三种方式:
1.重载less类模板(特化)。
2.自定义比较函数对象。
3.重载函数运算符。
#include <math.h>
#include <iostream>
#include <set>
using std::cout;
using std::endl;
using std::set;
using std::ostream;
template <typename Container>
void display(const Container& con)
{
for (auto& elem : con)
{
cout << elem << " ";
}
cout << endl;
}
class Point
{
public:
Point(int ix = 0, int iy = 0) : _ix(ix), _iy(iy) {}
double getDistance() const
{
return hypot(_ix, _iy);
}
int getX() const
{
return _ix;
}
int getY() const
{
return _iy;
}
friend ostream& operator<<(ostream& os, const Point& cls);
private:
int _ix;
int _iy;
};
ostream& operator<<(ostream& os, const Point& cls)
{
os << "(" << cls._ix
<< ", " << cls._iy
<< ")";
return os;
}
#if 0
//重载less类模板(特化)
//result : (-1, 2) (1, -2) (1, 2) (3, 2) (10, 3)
namespace std
{
template<>
struct less<Point>
{
bool operator()(const Point& lhs, const Point& rhs) const
{
cout << "struct Comparetion" << endl;
if (lhs.getDistance() < rhs.getDistance())
{
return true;
}
else if (lhs.getDistance() == rhs.getDistance())
{
if (lhs.getX() < rhs.getX())
{
return true;
}
else if (lhs.getX() == rhs.getX())
{
if (lhs.getY() < rhs.getY())
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
else
{
return false;
}
}
};
}
#endif
#if 0
//自定义比较函数对象
//result : (-1, 2) (1, -2) (1, 2) (3, 2) (10, 3)
struct compare
{
bool operator()(const Point& lhs, const Point& rhs) const
{
cout << "bool operator()(const Point& lhs, const Point& rhs) const" << endl;
if (lhs.getDistance() < rhs.getDistance()) return true;
else if (lhs.getDistance() == rhs.getDistance())
{
if (lhs.getX() < rhs.getX()) return true;
else if (lhs.getX() == rhs.getX())
{
if (lhs.getY() < rhs.getY())
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
else return false;
}
};
#endif
#if 1
//重载比较运算符,此函数内未完整比较,判断到_x即停止,不管_y。由于less内部的判等机制,导致Point(1, -2)被判等于Point(1, 2)。
//结果为(-1, 2) (1, 2) (3, 2) (10, 3)
bool operator<(const Point& lhs, const Point& rhs)
{
cout << "bool operator<(const Point& lhs, const Point& rhs)" << endl;
if (lhs.getDistance() < rhs.getDistance()) return true;
else if (lhs.getDistance() == rhs.getDistance())
{
if (lhs.getX() < rhs.getX()) return true;
else return false;
}
else return false;
}
#endif
void test2()
{
set<Point> poi = {
Point(10, 3),
Point(1, 2),
Point(-1, 2),
Point(1, -2),
Point(3, 2),
Point(1, 2),
};
display(poi);
}
int main(void)
{
test2();
return 0;
}