这两个比较表达式是否相同?

时间:2016-10-01 12:18:32

标签: c++

在另一个关于这两个函数是否具有相同逻辑的问题中似乎有一些disagreement

bool operator<(const screenPoint& left, const screenPoint& right){
  if (left.x < right.x) return true;
  else return left.y < right.y;
}

bool operator<(const screenPoint& left, const screenPoint& right){
  return left.x < right.x || left.y < right.y;
}

我已经盯着这些看了很长一段时间,我看不出它们会有什么不同的表现。在两者中,如果left.x < right.x,则他们都返回true。如果没有,那么他们都返回left.y < right.y的结果。正确?

如果没有,请有人详细说明。

另外,有人建议第一个与std::tie中词法排序的实现相同,是真的吗?

2 个答案:

答案 0 :(得分:6)

这两个是相同的(如果你修复了第一个if中缺少的括号),但它们没有实现严格的弱排序,所以你可能不想使用它们(它会在标准有序容器和算法中使用它们无效。)

证明:考虑a =(1,3)b =(2,2)的原始关系。然后a&lt; b和b&lt;一个。 (违反不对称财产)

正确的词典排序如下:

bool operator<(const screenPoint& left, const screenPoint& right){
    if (left.x < right.x) 
        return true;
    if (left.x > right.x)
        return false;
    return left.y < right.y;
}

如果您的成员只有<运算符而非>运算符,请将left.x > right.x替换为!(right.x < left.x)。这就是std::pairstd::tuple(由std::tie返回)实现词典比较的方式。

答案 1 :(得分:2)

不要只是猜测,拿你的编译器让它发出asm代码来检查差异。我的编译器(clang)为两个版本产生相同的结果:

#include <tuple>

__attribute__((noinline)) bool operatorLess1(const screenPoint& left, const screenPoint& right)
{
  if (left.x < right.x) return true;
  else return (left.y < right.y);
}

__attribute__((noinline)) bool operatorLess2(const screenPoint& left, const screenPoint& right) 
{
  return left.x < right.x || left.y < right.y;
}

__attribute__((noinline)) bool operatorLess3(const screenPoint& left, const screenPoint& right) 
{
  return std::tie(left.x, left.y) < std::tie(right.x, right.y);
}

__attribute__((noinline)) bool operatorLess4(const screenPoint& left, const screenPoint& right)
{
  if (left.x < right.x) return true;
  else if (left.x > right.x) return false;
  else return (left.y < right.y);
}

编译
clang++ -S -masm=intel -std=c++11 -O2 a.cpp

的产率:

__Z13operatorLess1RK11screenPointS1_:   ## @_Z13operatorLess1RK11screenPointS1_
    push    rbp
    mov rbp, rsp
Ltmp2:
    movss   xmm0, dword ptr [rsi]   ## xmm0 = mem[0],zero,zero,zero
    mov al, 1
    ucomiss xmm0, dword ptr [rdi]
    ja  LBB0_2
    movss   xmm0, dword ptr [rsi + 4] ## xmm0 = mem[0],zero,zero,zero
    ucomiss xmm0, dword ptr [rdi + 4]
    seta    al
LBB0_2:
    pop rbp
    ret
    .cfi_endproc


__Z13operatorLess2RK11screenPointS1_:   ## @_Z13operatorLess2RK11screenPointS1_
    .cfi_startproc
    push    rbp
    mov rbp, rsp
Ltmp5:
    movss   xmm0, dword ptr [rsi]   ## xmm0 = mem[0],zero,zero,zero
    mov al, 1
    ucomiss xmm0, dword ptr [rdi]
    ja  LBB1_2
    movss   xmm0, dword ptr [rsi + 4] ## xmm0 = mem[0],zero,zero,zero
    ucomiss xmm0, dword ptr [rdi + 4]
    seta    al
LBB1_2:
    pop rbp
    ret
    .cfi_endproc


__Z13operatorLess3RK11screenPointS1_:   ## @_Z13operatorLess3RK11screenPointS1_
    push    rbp
    mov rbp, rsp
Ltmp8:
    movss   xmm0, dword ptr [rdi]   ## xmm0 = mem[0],zero,zero,zero
    movss   xmm1, dword ptr [rsi]   ## xmm1 = mem[0],zero,zero,zero
    mov al, 1
    ucomiss xmm1, xmm0
    ja  LBB2_4
    ucomiss xmm0, xmm1
    jbe LBB2_3
    xor eax, eax
    pop rbp
    ret
LBB2_3:
    movss   xmm0, dword ptr [rsi + 4] ## xmm0 = mem[0],zero,zero,zero
    ucomiss xmm0, dword ptr [rdi + 4]
    seta    al
LBB2_4:                                 ## %_ZNSt3__1ltIJRKfS2_EJS2_S2_EEEbRKNS_5tupleIJDpT_EEERKNS3_IJDpT0_EEE.exit
    pop rbp
    ret
    .cfi_endproc

__Z13operatorLess4RK11screenPointS1_:   ## @_Z13operatorLess4RK11screenPointS1_
    .cfi_startproc
    push    rbp
    mov rbp, rsp
Ltmp11:
    movss   xmm0, dword ptr [rdi]   ## xmm0 = mem[0],zero,zero,zero
    movss   xmm1, dword ptr [rsi]   ## xmm1 = mem[0],zero,zero,zero
    mov al, 1
    ucomiss xmm1, xmm0
    ja  LBB3_4
    ucomiss xmm0, xmm1
    jbe LBB3_3
    xor eax, eax
    pop rbp
    ret
LBB3_3:
    movss   xmm0, dword ptr [rsi + 4] ## xmm0 = mem[0],zero,zero,zero
    ucomiss xmm0, dword ptr [rdi + 4]
    seta    al
LBB3_4:
    pop rbp
    ret
    .cfi_endproc

正如您所看到的,前两个版本相同,他们将比较x或直接比较y。正如interjay所指出的,std::tie版本是一个完整的弱排序,当left.x > left.y时返回0。实际上,它的代码与operatorLess4相同。