为什么我必须在POD类型中重载operator ==?

时间:2012-03-25 01:11:57

标签: c++ operator-overloading

我有一个像这样定义的结构:

struct Vec3 {
float x, y, z;
}

当我尝试在std::unique上使用std::vector<Vec3>时,我遇到了这个错误:

  

描述资源路径位置类型   首先与'_ 中的'operator =='不匹配。 _gnu_cxx :: __ normal_iterator&lt; _Iterator,_Container&gt; :: operator * with _Iterator = Vec3 *,_ Container = std :: vector&gt; == _ next。 _gnu_cxx :: __ normal_iterator&lt; _Iterator,_Container&gt; :: operator * with _Iterator = Vec3 *,_ Container = std :: vector&gt;'ModelConverter line 4351,external location:/ usr / include / c ++ / 4.4.6 / bits / stl_algo.h C / C ++问题

我理解 in 等式运算符和其他运算符中编译器的必要性(在这种情况下,*几乎肯定不是我的意思),但这是政策问题,或者是否有我不知道的技术原因?有一个默认赋值运算符,为什么没有默认的相等运算符?

4 个答案:

答案 0 :(得分:16)

没有技术原因。小心翼翼地,你可能会说这是因为C不允许你将两个结构与==进行比较,这是一个很好的理由;转到C ++时,这种行为转换是不明显的。 (据推测,C不支持的原因是,字段比较可能适用于某些结构,但绝对不是全部。)

从C ++的角度来看,如果你有私有领域怎么办?默认==在技术上暴露该字段(间接但仍然)。那么如果没有私有或受保护的数据成员,编译器只会生成operator==吗?

此外,有些类没有合理的相等定义(空类,不模型状态但是缓存它的类等),或者默认的相等性检查可能非常混乱(包装指针的类)

然后是继承。在继承的情况下决定为operator==做什么是很复杂的,并且编译器很容易做出错误的决定。 (例如,如果这就是C ++所做的那样,那么当你测试两个对象之间的相等性时,我们可能会得到关于为什么==总是成功的问题,这两个对象都是抽象基类的后代并且与它的引用一起使用。)

基本上,这是一个棘手的问题,即使考虑到你可以覆盖编译器决定的任何内容,编译器也不会更加安全。

答案 1 :(得分:5)

为什么必须提供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);
    }
};

其中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 );
}

现在,那是机器。将它应用到你的班级是什么样的......

struct Vec3
{
    float x, y, z;
};

嗯,这很简单:

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.
    }
};

免责声明:未经过严格测试的代码......: - )

答案 2 :(得分:1)

C ++ 20添加了此功能:

struct Vec3 {
    float x, y, z;
    auto operator<=>(const Vec3&) const = default;
    bool operator==(X const&) const = default;
}

目前仅在GCC和Clang干线中实现。请注意,当前默认的operator<=>等同于默认的operator==,但是存在accepted proposal to remove this。该提案建议将operator<=>设置为默认值也意味着(不等于今天)将operator==设置为扩展名。

Microsoft在https://devblogs.microsoft.com/cppblog/simplify-your-code-with-rocket-science-c20s-spaceship-operator/上有关于此功能的文档。

答案 3 :(得分:0)

您希望平等操作是什么?所有的领域都一样吗?它不会为你做出决定。