设为首页 加入收藏

TOP

4.8.5 相等与等价
2013-10-07 15:01:31 来源: 作者: 【 】 浏览:65
Tags:4.8.5 相等

4.8.5  相等与等价

相等(equality)与等价(equivalent)是两个极易被混淆的概念。一个简单快速的解释是:相等基于操作符==,即x==y;而等价基于<,即!(x<y)&&!(x>y),两者在语义上有很大差别。

对于简单类型(如int),相等和等价两者是一致的,例如5==10/2和!(5<10/2)&&! (5>10/2)。但对于大多数复杂类型和自定义类型,由于==和<操作符是两个不同的运算,比较原则可能不同,从而两者具有不同的意义。

之前的point类是一个很好的例子。p1(1,2,3)和p3(3,2,1)两者完全不相等,但等价,因为等价运算使用的是operator<,它比较依据的是成员变量的平方和:1+2*2+3*3 == 3*3+2*2+1。

operators库使用equality_comparable和equivalent明确地区分了相等与等价这两个概念。equality_comparable基于==,equivalent则基于<。但让人困扰的是它们最终都提供了操作符==,表现相同但含义非常不同。

了解相等与等价的区别非常重要,特别是当自定义类被用作容器的元素的时候。标准库中的关联容器(set、map)和排序算法使用的是等价关系的<操作符,而各种查找算法find使用的是相等关系的==操作符。

point类使用不同的规则定义了==和<,可以获得正确的比较和相等语义,下面是应用于标准容器的示范代码:

  1. point p0, p1(1,2,3), p2(5,6,7), p3(3,2,1);  
  2.  
  3. using namespace boost::assign;  
  4. vector<point> v = (list_of(p0), p1, p2, p3);  
  5.  
  6. BOOST_AUTO(pos, std::find(v.begin(), v.end(), point(1,2,3)));                                                                               //使用相等语义查找元素  
  7. for (; pos != v.end();                                  //查找下一个相等的元素  
  8.     pos = std::find(pos + 1, v.end(), point(1,2,3)))  
  9. {   pos->print();                                           //1, 2, 3   }  
  10.  
  11. pos = std::find(v.begin(), v.end(), point(2,1,3));  
  12. assert(pos == v.end());  

这段代码将只找到p1(1,2,3),并且最后一个assert断言成立,找不到值为(2,1,3)的point对象。

如果我们改变point的定义,不使用equality_comparable,而改用equivalent来实现==操作符(等价语义),那么我们不必单独定义==操作符,它将由equivalent自动用<操作符来实现。上面的测试代码的行为将完全不同,它会输出两个点:p1(1,2,3)和p3(3,2,1),并且断言失败。

在使用关联容器set和map时更需要留意,它们仅要求<操作符,因此是基于等价语义的,即使使用equality_comparable定义了==操作符,把point对象放入set或map也会产生equivalent的效果。

请读者谨慎地考虑自定义类需要什么样的语义,如果只关心类的等价语义,那么就用equivalent,如果想要精确地比较两个对象的值,就使用equality_comparable。

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇4.7.3 为第三态更名 下一篇4.8.4 复合运算概念

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: