关于c ++:定义泛型比较运算符

Define generic comparison operator

我想出了一个主意,定义一个通用的比较运算符,它可以与任何类型一起工作,这很有趣。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <cstring>
#include <iostream>

class A
{
    public:
        A(int id) : id(id) {}

    private:
        int id;
};

template <class T>
inline bool operator==(const T& a, const T& b)
{
    return memcmp(&a, &b, sizeof(a)) == 0; // implementation is unimportant (can fail because of padding)
}

int main()
{
    std::cout << (A(10) == A(10)) << std::endl; // 1
    std::cout << (A(10) == A(15)) << std::endl; // 0
}

我认为这可以帮助解决C++中缺省比较运算符的不足。

这是个可怕的主意吗?我想知道这样做是否会在某些情况下破坏任何东西?


这样做确实是个糟糕的主意。

如果某个类型未定义相等运算符,则很可能是因为您无法合理地比较该类型的两个对象以实现相等。

即使对于缺少的相等运算符是实现者的监督的情况,您将想到的任何"全部捕获"实现都极不可能做一些明智的事情。

所以总结一下:不要这样做!编译时错误比运行时错误要好;不要过早地添加一个最有把握的"解决方案",以隐藏实际问题,而是在发生编译时添加实际的解决方案。

?对于初学者,您提出的解决方案对于带有填充的类型、带有重载一元operator&的类型以及任何具有类似member的指针或引用的类型,甚至对于具有上述任何类别的任何成员或基的类型都是失败的。所以对于很多东西来说。


让我们上一个完全正常的课,比如说String。它是按照您的想法来实现的,使用一个指向new[]的缓冲区的char*

现在比较两个。显然,String("abc")==String("abc")。然而,由于两个指针不同,您的实现未能通过此测试。

相等性是由类语义定义的,而不是由对象内直接的位定义的。


是的,这是一个可怕的想法:如果指针未初始化:下面是一个失败的示例(因此此代码有两个不同的输出):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <cstring>
#include <iostream>

class A {
public:
  A(int id) : id(id) {}

private:
  int id;
  A* a;
};

template <class T> inline bool operator==(const T &a, const T &b) {
  return memcmp(&a, &b, sizeof(a)) == 0;
}

int main() {
  std::cout << (A(10) == A(10)) << std::endl; // 1
  std::cout << (A(10) == A(15)) << std::endl; // 0
}

输出:

1
2
0
0

对于两个指针,RAM初始内容的两个相同值的可能性非常小,那么另一个输出是:

1
2
1
0


略微说一下,我知道为具有大量成员的类编写相等运算符的最好方法是使用这个思想(此代码需要C++ 14):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <tuple>

struct foo
{
    int x    = 1;
    double y = 42.0;
    char z   = 'z';

    auto
    members() const
    {
        return std::tie(x, y, z);
    }
};

inline bool
operator==(const foo& lhs, const foo& rhs)
{
    return lhs.members() == rhs.members();
}

int
main()
{
    foo f1;
    foo f2;

    return f1 == f2;
}

编译器资源管理器上的代码