繁体   English   中英

如何比较 POD 类型的对象

[英]How to compare objects of POD types

这个例子:

#include <iostream>
#include <cstring>

struct A
{
    int  a;
    bool b;
};

bool foo( const A a1, const A a2 )
{
    return ( 0 == std::memcmp( &a1, &a2, sizeof( A ) ) );
}

int main()
{
    A a1 = A();
    a1.a = 5;a1.b = true;
    A a2 = A();
    a2.a = 5;a2.b = true;

    std::cout<<std::boolalpha << foo( a1, a2 ) << std::endl;
}

由于填充,将产生false

我无权访问foo function,也无法更改比较的方式。

假设bool占用 1 个字节(在我的系统上是这样),如果我将struct A更改为:

struct A
{
  int a;
  bool b;
  char dummy[3];
};

然后它在我的系统上工作正常(output 是true )。

我还能做些什么来解决上述问题(获得true的输出)?

由于结构中的填充,第一个不起作用。 两个对象的填充具有不同的位模式。

如果在使用之前使用memset设置 object 中的所有位,那么它将起作用:

A a1;
std::memset(&a1, 0, sizeof(A));
a1.a = 5;a1.b = true;

A a2;
std::memset(&a2, 0, sizeof(A));
a2.a = 5;a2.b = true;

在线演示:


顺便说一句,您也可以为 POD 编写operator<operator==等。

由于 C++11 我们可以使用元组进行简单的 POD 比较(元组对><>=<=运算符使用字典比较,更多信息: https://en.cppreference.com/w/cpp/utility/tuple/运营商_cmp ):

#include <iostream>
#include <tuple>

struct Point {
    int x;
    int y;
    int z;    
};


auto pointToTuple(const Point& p) {
    return std::make_tuple(p.x, p.y, p.z);
}

bool operator==(const Point& lhs, const Point& rhs ) {
    return pointToTuple(lhs) == pointToTuple(rhs);
}

bool operator<(const Point& lhs, const Point& rhs ) {
    return pointToTuple(lhs) < pointToTuple(rhs);
}

int main()
{

    Point a{1, 2, 3};
    Point b{1, 2, 3};
    Point c{2, 2, 2};

    std::cout << (pointToTuple(a) == pointToTuple(b) ? "true" : "false") << "\n"; //true
    std::cout << (pointToTuple(a) == pointToTuple(c) ? "true" : "false") << "\n"; //false

    std::cout << (a == b ? "true" : "false") << "\n"; //true
    std::cout << (a == c ? "true" : "false") << "\n"; //false

    std::cout << (a < b ? "true" : "false") << "\n"; //false
    std::cout << (a < c ? "true" : "false") << "\n"; //true

}

C++20 应该为我们带来默认比较( https://en.cppreference.com/w/cpp/language/default_comparisons )。 因此,如果 class 将operator<=>定义为默认值,编译器将自动生成==!=<<=>>=运算符及其代码:

struct Point {
    int x;
    int y;
    int z;    

    auto operator<=>(const Point&) const = default;
};

在 C++14 及以上版本中,您可以使用此库: https://github.com/apolukhin/magic_get/来提取 POD 的成员类型。 你可以编写通用比较运算符,它不需要原始 object 的 memsetting memory 来擦除填充,如下所示:

#include "boost/pfr/precise.hpp"
template<typename T>
void foo(const T& a, const T& b)
{
    return boost::pfr::flat_less<T>{}(a, b);
}

这种方法的优点是不修改创建对象的代码(这在不受您控制时可能很有价值),但它也会生成额外的二进制代码,并且使用 PFR 库进行编译会更慢。

仍然 - 它是最灵活和最干净的,因为简单的 memcmp 不会给您真正的语义能力(例如,当您在 POD 的子类型上使用自定义比较运算符时)。


PS:使用 PFR 库,您可以使用 POD 执行多种其他操作,例如打印它们、迭代成员等。在此处查看更多示例:

http://apolukhin.github.io/magic_get/boost_precise_and_flat_reflectio/short_examples_for_the_impatient.ZFC35FDC70D5FC69D269883A8E2

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM