我有一个像这样定义的结构:
struct Vec3 {
float x, y, z;
}
Run Code Online (Sandbox Code Playgroud)
当我试图使用std::uniquea时std::vector<Vec3>,我遇到了这个错误:
说明资源路径位置类型与'_ first '中的'operator =='不匹配._gnu_cxx :: __ normal_iterator <_Iterator,_Container> :: operator*with _Iterator = Vec3*,_ _Container = std :: vector> == _ next._gnu_cxx :: __ normal_iterator <_Iterator,_Container> :: operator*with _Iterator = Vec3*,_ Container = std :: vector>'ModelConverter line 4351,external location:/usr/include/c++/4.4.6/bits/stl_algo.h C/C++问题
我理解编译器的naievite 在等式运算符和其他运算符中的必要性(在这种情况下,*几乎肯定不是我的意思),但这是一个政策问题,还是有技术原因,我不知道?有一个默认赋值运算符,为什么没有默认的相等运算符?
Joh*_*eek 17
没有技术原因.小心翼翼地,你可能会说这是因为C不允许你比较两个结构==,这是一个很好的理由; 转到C++时,这种行为转换是不明显的.(据推测,C不支持的原因是,字段比较可能适用于某些结构,但绝对不是全部.)
从C++的角度来看,如果你有私有领域怎么办?默认==技术上暴露该字段(间接但仍然).那么operator==如果没有私有或受保护的数据成员,编译器是否只生成一个?
此外,有些类没有合理的相等定义(空类,不模型状态但是缓存它的类等),或者默认的相等性检查可能非常混乱(包装指针的类).
然后是继承.operator==在继承的情况下决定要做什么是很复杂的,并且编译器很容易做出错误的决定.(例如,如果这就是C++所做的那样,那么==当你测试两个对象之间的相等性时,我们可能会得到一些问题,这两个对象既是抽象基类的后代又是与它的引用一起使用.)
基本上,这是一个棘手的问题,即使考虑到您可以覆盖编译器决定的任何内容,编译器也不会更加安全.
您必须提供operator==的问题与为什么必须提供某些比较功能的问题不同.
关于后者,你需要提供比较逻辑的原因是,元素明确的平等很少是合适的.例如,考虑一个带有数组的POD结构char.如果它用于保存以零结尾的字符串,那么两个这样的结构可以在二进制级别上比较不相等(由于字符串中的零字节之后的任意内容)但在逻辑上是等效的.
另外,这里有其他答案提到的所有C++级复杂性,例如特别棘手的多态相等(你真的不希望编译器选择!).
所以,基本上,没有好的默认选择,所以选择是你的.
关于前一个问题,这是你真正要求的问题,你为什么要提供operator==?
如果定义operator<和operator==,然后在命名空间中的操作定义std::rel_ops可以在休息填写.据推测,operator==需要的原因是根据operator<(然后需要两次比较)实施它将是不必要的低效率.然而,选择这两个运算符作为基础是完全令人困惑的,因为它使用户代码冗长和复杂,并且在某些情况下效率低得多!
恕我直言比较运算符的最佳基础是三值compare函数,例如std::string::compare.
给定一个成员函数变量comparedTo,然后您可以使用如下所示的奇怪重复模板模式类来提供完整的运算符集:
template< class Derived >
class ComparisionOps
{
public:
friend int compare( Derived const a, Derived const& b )
{
return a.comparedTo( b );
}
friend bool operator<( Derived const a, Derived const b )
{
return (compare( a, b ) < 0);
}
friend bool operator<=( Derived const a, Derived const b )
{
return (compare( a, b ) <= 0);
}
friend bool operator==( Derived const a, Derived const b )
{
return (compare( a, b ) == 0);
}
friend bool operator>=( Derived const a, Derived const b )
{
return (compare( a, b ) >= 0);
}
friend bool operator>( Derived const a, Derived const b )
{
return (compare( a, b ) > 0);
}
friend bool operator!=( Derived const a, Derived const b )
{
return (compare( a, b ) != 0);
}
};
Run Code Online (Sandbox Code Playgroud)
where compare是一个重载函数,例如:
template< class Type >
inline bool lt( Type const& a, Type const& b )
{
return std::less<Type>()( a, b );
}
template< class Type >
inline bool eq( Type const& a, Type const& b )
{
return std::equal_to<Type>()( a, b );
}
template< class Type >
inline int compare( Type const& a, Type const b )
{
return (lt( a, b )? -1 : eq( a, b )? 0 : +1);
}
template< class Char >
inline int compare( basic_string<Char> const& a, basic_string<Char> const& b )
{
return a.compare( b );
}
template< class Char >
inline int compareCStrings( Char const a[], Char const b[] )
{
typedef char_traits<Char> Traits;
Size const aLen = Traits::length( a );
Size const bLen = Traits::length( b );
// Since there can be negative Char values, cannot rely on comparision stopping
// at zero termination (this can probably be much optimized at assembly level):
int const way = Traits::compare( a, b, min( aLen, bLen ) );
return (way == 0? compare( aLen, bLen ) : way);
}
inline int compare( char const a[], char const b[] )
{
return compareCStrings( a, b );
}
inline int compare( wchar_t const a[], wchar_t const b[] )
{
return compareCStrings( a, b );
}
Run Code Online (Sandbox Code Playgroud)
现在,这就是机器.将它应用到你的班级是什么样的......
struct Vec3
{
float x, y, z;
};
Run Code Online (Sandbox Code Playgroud)
?
嗯,这很简单:
struct Vec3
: public ComparisionOps<Vec3>
{
float x, y, z;
int comparedTo( Vec3 const& other ) const
{
if( int c = compare( x, other.x ) ) { return c; }
if( int c = compare( y, other.y ) ) { return c; }
if( int c = compare( z, other.z ) ) { return c; }
return 0; // Equal.
}
};
Run Code Online (Sandbox Code Playgroud)
免责声明:没有经过严格测试的代码... :-)