19.理解相等(equality)和等价(equivalence)的区别
STL中,对两个对象进⾏⽐较,看他们的值是否相同,涉及到两个概念,相等和等价。
相等的概念是基于operator == 的。如果表达式"x ==y"返回真,则x和y的值相等,否则就不相等。
等价是以“在已排序的区间中对象值的相对顺序”为基础的。
考虑std::set s,如果两个Widget w1和w2,在s的排列顺序中哪个也不在另外⼀个的前⾯,那么,w1和w2对于s⽽⾔有等价的值。std::set的默认⽐较函数是std::less, ⽽在默认情况下std::less只是简单地调⽤了针对Widget的operator <, 所以,如果下⾯的表达式结果为真,则w1和w2对于operator < 有等价的值:
!(w1 < w2)&&!(w2 < w1)
这⾥的含义是:如果两个值中的任何⼀个(按照⼀定的排序准则)都不在另外⼀个的前⾯,那么这两个值(按照这⼀准则)就是等价的。
在⼀般情形下,⼀个关联容器的⽐较函数并不是operator <, 甚⾄也不是less,它是⽤户定义的判别式(predicate)。
每个标准关联容器都通过key_compare成员函数是排序判别式可被外部使⽤,所以,如果下⾯的表达式为true,则按照关联容器c的排序准则,两个对象x和y有等价的值:
!c.key_compare()(x, y)&&!c.key_compare()(y, x)
为了充分领会相等和等价的区别,考虑⼀个不区分⼤⼩写的⽐较函数IgnoreCasLess,它把"PERSEPHONE"和"persephone"看成是等价的。
std::string ConvertToLower(const std::string& one)
{
transform和convert的区别...
}
auto IgnoreCaseLess =[](const std::string& lhs,const std::string& rhs){ConvertToLower(lhs)<ConvertToLower(rhs);};
创建⼀个不区分⼤⼩学的std::set容器datas。
std::set<std::string, IgnoreCaseLess> datas;
如果我们把字符串"PERSEPHONE"和"persephone"插⼊到集合datas中,则只有第⼀个字符串会被插⼊,因为第⼆个和第⼀个等价:
datas.insert("PERSEPHONE");// 插⼊
datas.insert("persephone");// 插⼊失败
如果我们使⽤std::set的成员函数find()来查字符串"persephone",则该查会成功:
if(datas.find("persephone")!= d())...// 成功到的是**"PERSEPHONE"**
但如果我们使⽤⾮成员的find()算法,则查失败:
if(std::find(datas.begin(), d(),"persephone")!= d())// 不到
这是因为"PERSEPHONE"与"Persephone"等价(按照IgnoreCaseLess),但并不相等。
因此,对于序列容器(set multiset map multimap)应该优先选⽤⾃⼰的成员函数⽽不是与之对应的算法,这样才能保证都是使⽤的是⽤于插⼊的排序函数来进⾏的相应处理,保证结果的⼀致性。
那么,关联容器为什么是基于等价⽽不是相等的。毕竟,绝⼤多数⼈对于相等有⼀种直觉,⽽对于等价则不然。关联容器总是保持排序的,所以每个容器必须有⼀个⽐较函数来决定保持这样的顺序。等价的定义正是通过⽐较函数确定的。因此,关联容器要为使⽤的每个容器指定⼀个⽐较函数。如果该关联容器使⽤相等来决定两个对象是否相等,那么每个关联容器除了应⽤于排序的⽐较函数外,还需要另外⼀个⽐较函数来决定两个对象是否相等。总之,使⽤单⼀的⽐较函数(⽤于排序),并把等价关系作为判定两个元素是否"相同"的依据,使得标准关联容器避免了⼀⼤堆“若使⽤两个⽐较函数带来的问题”,这样做避免了在标准关联容器中混合使⽤相等和等价带来的混乱。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论