关于与memcmp
进行成员比较产生相同结果的前提条件==
,虽然在实践中经常满足这个前提条件,但它有点脆弱。
从理论上讲,更改编译器或编译器选项可以打破该先决条件。更令人担忧的是,代码维护(所有编程工作的 80% 是维护,IIRC)可以通过添加或删除成员、使类多态、添加自定义==
重载等来破坏它。正如其中一条评论中提到的,前提条件可以适用于静态变量,但不能适用于自动变量,然后创建非静态对象的维护工作可能会做坏事™。
关于是使用memcmp
还是按成员方式==
为类实现==
运算符的问题,首先,这是一种错误的二分法,因为这些不是唯一的选择。
例如,就函数而言,使用自动生成关系运算符重载compare
可以减少工作量并且更易于维护。该std::string::compare
函数是这种函数的一个示例。
其次,选择什么实现的答案很大程度上取决于您认为重要的内容,例如:
是否应该寻求最大化运行时效率,或者
是否应该寻求创建最清晰的代码,或者
应该寻求最简洁、最快的代码编写方式,还是
是否应该寻求使该类最安全地使用,或者
别的东西,也许?
生成关系运算符。
您可能听说过 CRTP,即奇怪重复的模板模式。我记得它是为了处理生成关系运算符重载的要求而发明的。不过,我可能会将其与其他内容混为一谈,但无论如何:
template< class Derived >
struct Relops_from_compare
{
friend
auto operator!=( const Derived& a, const Derived& b )
-> bool
{ return compare( a, b ) != 0; }
friend
auto operator<( const Derived& a, const Derived& b )
-> bool
{ return compare( a, b ) < 0; }
friend
auto operator<=( const Derived& a, const Derived& b )
-> bool
{ return compare( a, b ) <= 0; }
friend
auto operator==( const Derived& a, const Derived& b )
-> bool
{ return compare( a, b ) == 0; }
friend
auto operator>=( const Derived& a, const Derived& b )
-> bool
{ return compare( a, b ) >= 0; }
friend
auto operator>( const Derived& a, const Derived& b )
-> bool
{ return compare( a, b ) > 0; }
};
鉴于上述支持,我们可以调查您的问题可用的选项。
实现A:减法比较。
这是一个提供全套关系运算符的类,而无需使用memcmp
or ==
:
struct Vector
: Relops_from_compare< Vector >
{
int x, y, z;
// This implementation assumes no overflow occurs.
friend
auto compare( const Vector& a, const Vector& b )
-> int
{
if( const auto r = a.x - b.x ) { return r; }
if( const auto r = a.y - b.y ) { return r; }
return a.z - b.z;
}
Vector( const int _x, const int _y, const int _z )
: x( _x ), y( _y ), z( _z )
{}
};
实现 B:比较通过memcmp
.
这是使用memcmp
;实现的同一个类。我想你会同意这段代码可以更好地扩展并且更简单:
struct Vector
: Relops_from_compare< Vector >
{
int x, y, z;
// This implementation requires that there is no padding.
// Also, it doesn't deal with negative numbers for < or >.
friend
auto compare( const Vector& a, const Vector& b )
-> int
{
static_assert( sizeof( Vector ) == 3*sizeof( x ), "!" );
return memcmp( &a, &b, sizeof( Vector ) );
}
Vector( const int _x, const int _y, const int _z )
: x( _x ), y( _y ), z( _z )
{}
};
实现 C:逐个成员比较。
这是一个使用成员比较的实现。它没有强加任何特殊要求或假设。但它更多的是源代码。
struct Vector
: Relops_from_compare< Vector >
{
int x, y, z;
friend
auto compare( const Vector& a, const Vector& b )
-> int
{
if( a.x < b.x ) { return -1; }
if( a.x > b.x ) { return +1; }
if( a.y < b.y ) { return -1; }
if( a.y > b.y ) { return +1; }
if( a.z < b.z ) { return -1; }
if( a.z > b.z ) { return +1; }
return 0;
}
Vector( const int _x, const int _y, const int _z )
: x( _x ), y( _y ), z( _z )
{}
};
实现 D:compare
就关系运算符而言。
这是一种颠倒事物自然顺序的实现方式,通过compare
和<
实现==
,直接提供并根据std::tuple
比较(使用std::tie
)实现。
struct Vector
{
int x, y, z;
friend
auto operator<( const Vector& a, const Vector& b )
-> bool
{
using std::tie;
return tie( a.x, a.y, a.z ) < tie( b.x, b.y, b.z );
}
friend
auto operator==( const Vector& a, const Vector& b )
-> bool
{
using std::tie;
return tie( a.x, a.y, a.z ) == tie( b.x, b.y, b.z );
}
friend
auto compare( const Vector& a, const Vector& b )
-> int
{
return (a < b? -1 : a == b? 0 : +1);
}
Vector( const int _x, const int _y, const int _z )
: x( _x ), y( _y ), z( _z )
{}
};
如给定的,使用 eg 的客户端代码>
需要一个using namespace std::rel_ops;
.
替代方法包括将所有其他运算符添加到上述(更多代码),或使用 CRTP 运算符生成方案,该方案根据<
和=
(可能效率低下)实现其他运算符。
实现 E:通过手动使用<
和进行比较==
。
这个实现是没有应用任何抽象的结果,只是敲打键盘并直接写下机器应该做什么:
struct Vector
{
int x, y, z;
friend
auto operator<( const Vector& a, const Vector& b )
-> bool
{
return (
a.x < b.x ||
a.x == b.x && (
a.y < b.y ||
a.y == b.y && (
a.z < b.z
)
)
);
}
friend
auto operator==( const Vector& a, const Vector& b )
-> bool
{
return
a.x == b.x &&
a.y == b.y &&
a.z == b.z;
}
friend
auto compare( const Vector& a, const Vector& b )
-> int
{
return (a < b? -1 : a == b? 0 : +1);
}
Vector( const int _x, const int _y, const int _z )
: x( _x ), y( _y ), z( _z )
{}
};
选择什么。
考虑最有价值的可能方面的列表,例如安全性、清晰度、效率、简短性,评估上述每种方法。
然后选择对你来说显然是最好的一种,或者看起来同样最好的方法之一。
指导:为了安全起见,您不想选择方法 A,减法,因为它依赖于对值的假设。请注意,选项 B, , 作为一般情况的实现也是不安全的,但对于和memcmp
可以做得很好。为了提高效率,您应该更好地MEASURE,使用相关的编译器选项和环境,并记住 Donald Knuth 的格言:“过早的优化是万恶之源”(即花时间在上面可能会适得其反)。==
!=