在另一个关于这两个函数是否具有相同逻辑的问题中似乎有一些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
中词法排序的实现相同,是真的吗?
答案 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::pair
和std::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
相同。