C++学习笔记:容器的自定义类型构造时排序问题

某些容器初始化时,由于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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值