如何定义运算符< on an n-tuple that satisfies a strict weak ordering [duplicate]

问题描述 投票:0回答:7

如何在n元组(例如3元组)上定义

operator<
,使其满足严格弱排序概念?我知道 boost 库有正确定义的元组类
operator<
但由于某些原因我无法使用它。

c++ tuples operator-overloading strict-weak-ordering
7个回答
75
投票

严格弱排序

这是一个数学术语,用于定义两个对象之间的关系。
它的定义是:

如果 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 b        b < a     false

a is less than b            a < b     true
a is less than b            b < a     false

b is less than a            a < b     false
b is less than a            b < a     true

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

正式定义:
严格弱排序

计算机科学:
严格弱序

它与运营商有何关系:
比较器


顺便说一句,我们可以手动实现严格的弱排序。但我们可以简单地使用

std::tuple
来完成它,它已经为您实现了。您只需创建一个元组而不复制对象。

struct S
{
     ThingA   a;
     ThingB   b;
};
bool operator<(S const& lhs, S const& rhs)
{
    return std::tie(lhs.a, lhs.b) < std::tie(rhs.a, rhs.b);
}

注意:这假设

thingA
thingB
本身已经实现了严格的弱排序。

我们也可以用同样的方式实现平等:

bool operator==(S const& lhs, S const& rhs)
{
    return std::tie(lhs.a, lhs.b) == std::tie(rhs.a, rhs.b);
}

再次注意:这假设

thingA
thingB
已经实现了相等性。


46
投票
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 是最重要的,a3 是最不重要的。

这可以无限地继续,您也可以例如将其应用于 T 的向量,迭代 a[i] 的比较 < a[i+1] / a[i+1] < a[i]. An alternate expression of the algorithm would be "skip while equal, then compare":

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

当然,如果比较成本很高,您可能需要缓存比较结果。


[编辑]删除了错误的代码


[编辑] 如果不仅仅是

operator<
可用,我倾向于使用该模式

if (a1 != b1)
  return a1 < b1;

if (a2 != b2)
  return a2 < b2;

...

35
投票

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

C++11解决方案

C++11 及以上版本提供

std::tuple<T...>
,您可以使用它来存储数据。
tuple
有一个匹配的
operator<
,它最初比较最左边的元素,然后沿着元组工作,直到结果明确。这适合提供例如所期望的严格的弱排序
std::set
std::map

如果您在某些其他变量中有数据(例如

struct
中的字段),您甚至可以使用
std::tie()
创建一个元组 ofreferences,然后可以将其与另一个这样的元组进行比较。这样可以轻松地在用户定义的
operator<
/
class
类型中为特定成员数据字段编写
struct

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_);
}

6
投票

您可以简单地使用三元素向量,它已经有运算符<() suitably defined. This has the advantage that it extends to N-elements without you having to do anything.


6
投票

基本流程应遵循以下原则:如果第 K 个元素不同,则返回较小的元素,否则转到下一个元素。下面的代码假设您没有有一个boost元组,否则您将使用

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;

2
投票

即使你不能使用 boost 版本,你也应该能够修改代码。我从 std::pair 中删掉了这个 - 我猜 3 元组会是相似的。

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

编辑:正如一些人所指出的,如果您从标准库中窃取代码以在代码中使用,则应该重命名前面有下划线的内容,因为这些名称是保留的。


0
投票

请注意,有趣的是,始终返回

operator <
false
满足严格弱排序的要求。

© www.soinside.com 2019 - 2024. All rights reserved.