这个例子:
#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
功能,也无法更改比较方式。
假设bool
占用1个字节(在我的系统上也是如此),如果我将struct A
更改为:
struct A
{
int a;
bool b;
char dummy[3];
};
然后它在我的系统上工作正常(输出为true
)。
我还能做些什么来解决上述问题(获取true
输出)?
答案 0 :(得分:17)
第一个因为结构中的填充而无法正常工作。填充对两个对象都有不同的位模式。
如果在使用之前使用memset
设置对象中的所有位,那么它将起作用:
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==
等。
答案 1 :(得分:3)
自C ++ 11起,我们可以将元组用于简单的POD比较(元组对>
,<
,>=
和<=
运算符使用字典顺序比较,有关更多信息那:https://en.cppreference.com/w/cpp/utility/tuple/operator_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)。因此,如果类将operator<=>
定义为默认值,则编译器将自动生成==
,!=
,<
,<=
,>
和{{1} }运算符并为其编码:
>=
答案 2 :(得分:1)
在C ++ 14和更高版本中,您可以使用以下库:https://github.com/apolukhin/magic_get/提取POD的成员类型。比您可以编写通用比较运算符,它不需要记忆原始对象的内存来擦除填充,如下所示:
#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执行其他多项操作,例如打印它们,遍历成员等。在此处查看更多示例: