运营商<和严格的弱秩序

如何在n元组(例如3元组)上定义operator<它满足严格的弱排序概念? 我知道boost库具有正确定义的operator<元组类,但由于某些原因,我无法使用它。

 if (a1 < b1) return true; if (b1 < a1) return false; // a1==b1: continue with element 2 if (a2 < b2) return true; if (b2 < a2) return false; // a2 == b2: continue with element 3 if (a3 < b3) return true; return false; // early out 

这是由a1指定的元素最重要,最不重要的。

这可以继续无限的,你也可以例如将它应用于T的向量,迭代比较[i] <a [i + 1] / a [i + 1] <a [i]。 该算法的另一种表达方式是“同时跳过,然后比较”:

 while (i<count-1 && !(a[i] < a[i+1]) && !(a[i+1] < a[i]) ++i; return i < count-1 && a[i] < a[i+1]; 

当然,如果比较费用昂贵,您可能需要缓存比较结果。


删除了错误的代码

严格的弱排序

这是定义两个对象之间关系的数学术语。
其定义是:

如果f(x,y)和f(y,x)都是假的,则两个对象x和y是等价的。 请注意,一个对象总是(通过无反射性不变)等同于它本身。

就C ++而言,这意味着如果您有两个给定类型的对象,则应该在与运算符<进行比较时返回以下值。

 X a; X b; Condition: Test: Result a is equivalent to b: a < b false a is equivalent to bb < a false a is less than ba < b true a is less than bb < a false b is less than aa < b false b is less than ab < a true 

你如何定义等价/更少完全取决于你的对象的类型。

查看关于这个主题的SGI页面:
http://www.sgi.com/tech/stl/StrictWeakOrdering.html

…一个很老的问题的新答案,但现有的答案错过了C ++ 11的简单解决方案…

C ++ 11解决方案

C ++ 11向前提供了std::tuple<T...> ,你可以使用它来存储你的数据。 tuple s有一个匹配的operator<最初比较最左边的元素,然后沿着元组工作,直到结果清晰。 这适合于提供例如std::setstd::map期望的严格的弱顺序

如果你有一些其他变量的数据(例如struct字段),甚至可以使用std::tie()创建一个引用元组然后可以将这个元组与另一个这样的元组进行比较。 这样可以很容易地为用户定义的class / struct类型中的特定成员数据字段写入operator<

 struct My_Struct { int a_; double b_; std::string c_; }; bool operator<(const My_Struct& lhs, const My_Struct& rhs) { return std::tie(lhs.a_, lhs.b_, lhs.c_) < std::tie(rhs.a_, rhs.b_, rhs.c_); } 

你可以简单地使用三元素向量,它已经有适当定义的operator <()了。 这有一个好处,就是它不需要做任何事情就可以扩展到N元素。

基本流程应该是: 如果第K个元素是不同的,则返回哪个更小否则转到下一个元素 。 下面的代码假设你没有提升元组,否则你会使用get<N>(tuple)并没有问题的开始。

 if (lhs.first != rhs.first) return lhs.first < rhs.first; if (lhs.second != rhs.second) return lhs.second< rhs.second; return lhs.third < rhs.third; 

即使你不能使用boost版本,你也应该能够对代码进行剔除。 我从std :: pair中挑出了这个 – 一个3元组将会类似我猜。

 return (_Left.first < _Right.first || !(_Right.first < _Left.first) && _Left.second < _Right.second); 

编辑:正如一些人已经指出的,如果你从标准库中窃取代码来使用你的代码,你应该重命名前面有下划线的东西,因为这些名字是保留的。