c++tuple运算符重载/tuple比较

c++中STL中tuple类的运算符重载
头文件:

#include<tuple>

总结


tuple类中重载了

“==”, “!=”, “>”, “>=”, “<”, “<=”

等比较运算操作符,但实现都是靠

“==“和”<”

而这两个运算符的实现是通过递归的方法依次比较tuple类对象中的元素。
所以tuple类中的元素只需重载"<“和”=="即可实现所有运算符的重载。


详解:


主要注意源代码中的 “==” 和 “<” 重载,这也是STL中的主要运算符。
其余运算符通过调用这两个运算符得到。

STL中源代码(粗略浏览重载的操作符和汉字注释即可)

// OPERATORS FOR tuple
template <class... _Types1, class... _Types2>
_NODISCARD constexpr bool operator==(const tuple<_Types1...>& _Left, const tuple<_Types2...>& _Right) {
    static_assert(sizeof...(_Types1) == sizeof...(_Types2), "cannot compare tuples of different sizes");
    //错误警示,若两个tuple函数的规格不一,assert函数会向stderr端传入"cannot compare tuples of different sizes",报错
    return _Left._Equals(_Right);
    //_Equal是tuple类的成员函数,操作符重载的重点,注意!一会探究
}

template <class... _Types1, class... _Types2>
_NODISCARD constexpr bool operator!=(const tuple<_Types1...>& _Left, const tuple<_Types2...>& _Right) {
    return !(_Left == _Right);
    //间接调用==,不必深究
}

template <class... _Types1, class... _Types2>
_NODISCARD constexpr bool operator<(const tuple<_Types1...>& _Left, const tuple<_Types2...>& _Right) {
    static_assert(sizeof...(_Types1) == sizeof...(_Types2), "cannot compare tuples of different sizes");
    //错误警示,若两个tuple函数的规格不一,assert函数会向stderr端传入"cannot compare tuples of different sizes",报错
    return _Left._Less(_Right);
    //_Less是tuple类的成员函数,也是操作符重载的关键
}

template <class... _Types1, class... _Types2>
_NODISCARD constexpr bool operator>=(const tuple<_Types1...>& _Left, const tuple<_Types2...>& _Right) {
    return !(_Left < _Right);
    //调用<
}

template <class... _Types1, class... _Types2>
_NODISCARD constexpr bool operator>(const tuple<_Types1...>& _Left, const tuple<_Types2...>& _Right) {
    return _Right < _Left;
    //调用<
}

template <class... _Types1, class... _Types2>
_NODISCARD constexpr bool operator<=(const tuple<_Types1...>& _Left, const tuple<_Types2...>& _Right) {
    return !(_Right < _Left);
    //调用<
}
}

tuple类中重载了 “==”, “!=”, “>”, “>=”, “<”, “<=” 等比较运算操作符

但从代码上面可以看出,其中主要重载了"==", "<"这两个运算符,
其他操作符通过调用这两个运算符得出答案。

而这两个操作符重载的关键在于:_Less()和_Equals()。
通过调用方式可以得出这是tuple类中的成员函数。

继续查看源代码:

template <class... _Other>
    constexpr bool _Equals(const tuple<_Other...>& _Right) const {
        return _Myfirst._Val == _Right._Myfirst._Val && _Mybase::_Equals(_Right._Get_rest());
    }

    template <class... _Other>
    constexpr bool _Less(const tuple<_Other...>& _Right) const {
        return _Myfirst._Val < _Right._Myfirst._Val
               || (!(_Right._Myfirst._Val < _Myfirst._Val) && _Mybase::_Less(_Right._Get_rest()));
    }

明显有递归调用,以_Equal为例,探究成员函数运算过程:

return _Myfirst._Val == _Right._Myfirst._Val && _Mybase::_Equals(_Right._Get_rest());

先说题外话:

Tuple的实现原理:tuple类是通过递归实现。
如要建立tuple类的一个对象,名为temp

tuple<int, string, double> temp;

则它是先建立一个tuple类:base

tuple<> base

再以之前的base类为基础,建立新的tuple类,继续命名为base

tuple<double> base

继续以之前的base类为基础,建立新的tuple类,命名为base

tuple<string, double> base

最后以名为base的tuple类建立目标类

tuple<int, string, double> temp;

具体可以百度tuple实现原理,
大意就是每个tuple中都有去掉首元素后其余元素的tuple类对象:base

比如:

tuple<int,string,double> one//此对象中有一个成员变量:tuple<string, double> base
tuple<int,double, char> two//此对象中有一个成员变量:tuple<string, char> base
tuple<int, int, int> three//此对象中有一个成员变量:tuple<int, int> base

回到主题:

return _Myfirst._Val == _Right._Myfirst._Val && _Mybase::_Equals(_Right._Get_rest());

_Myfirst.val是当前tuple类的对象中第一个元素的值。
_Get_rest()返回当前tuple类对象中的base类,也就是除去第一个元素后剩下的元素构成的tuple类的对象。

这是比较第一个元素是否相等

 _Myfirst._Val == _Right._Myfirst._Val 

这就相当于继续比较剩下的元素是否相等,继续调用Equal,是一个递归算法

_Mybase::_Equals(_Right._Get_rest());

将结果用&&结合,再return

return _Myfirst._Val == _Right._Myfirst._Val && _Mybase::_Equals(_Right._Get_rest());

这就是_Equal函数的运算过程。
_Less同理。


版权声明:本文为lzn211原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。