有许多原始结构(数百个),用于在两个组件(例如播放器和服务器)之间传输数据。它们中没有方法,只有原始数据。 任务是编写所有请求和答案,以便能够在没有服务器的情况下重放播放器场景(我们记住所有问题和所有答案,即纯函数)。 所以任务是把这个结构放在没有比较器的地图中。现在我们使用memcmp,它允许不考虑这个结构的变化而且它是紧凑的,但填充等问题太多了。
是否有可能获得像getHashValue或任何带有c ++元编程的默认比较器的smth? 条件: 1)我不想为每个结构创建一个比较器。 2)如果字段被添加或删除,如果它破坏现有行为并需要修复,我想要出错。 3)我不想用结构定义来改变头文件。
结构示例
struct A {
int a;
int b;
c c;
}
bool operator<(const A& a1, const A& a2)
{
if (a1.a != a2.a) return a1.a < a2.a;
if (a1.b != a2.b) return a1.b < a2.b;
if (a1.c != a2.c) return a1.c < a2.c;
return false;
}
我可以考虑使用其他语言来实现这个确切的部分(收集问题/答案),如果它不需要再次描述该语言的所有结构。
答案 0 :(得分:3)
我想你可以根据memcmp
编写自己的比较运算符。
bool operator<(const A &lhs, const A &rhs) {
return memcmp(&lhs, &rhs, sizeof(A)) < 0;
}
当然,为每个对象编写这些可能是一个负担,所以你可以为此编写一个模板。虽然没有一些SFINAE,但它会覆盖太多类型。
#include <type_traits>
#include <cstring>
template<typename T>
std::enable_if_t<std::is_pod_v<std::decay_t<T> //< Check if POD
&& !std::is_fundamental_v<std::decay_t<T>>>, //< Don't override for fundamental types like 'int'
bool>
operator<(const T &lhs, const T &rhs) {
return memcmp(&lhs, &rhs, sizeof(std::decay_t<T>)) < 0;
}
编辑:请注意,此技术要求您对结构进行零初始化。
答案 1 :(得分:3)
在C ++ 17中,如果你愿意(A)硬编码每个结构中有多少个元素,你可以将其关闭,以及(B)为结构中每个元素数量的计数编写或生成代码
template<std::size_t N>
using size_k = std::integral_constant<std::size_t, N>;
template<class T>
auto auto_tie( size_k<0>, T&& t ) {
return std::tie();
}
template<class T>
auto auto_tie( size_k<1>, T&& t ) {
auto& [ x0 ] = std::forward<T>(t);
return std::tie( x0 );
}
template<class T>
auto auto_tie( size_k<2>, T&& t ) {
auto& [ x0, x1 ] = std::forward<T>(t);
return std::tie( x0, x1 );
}
// etc
现在,在相关结构的命名空间中,编写
struct foo {
int x;
};
struct bar {
int a, b;
};
size_k<1> elems( foo const& ) { return {}; }
size_k<2> elems( bar const& ) { return {}; }
elems
函数,返回计算了多少元素的size_k
。
现在在结构体的命名空间中,写一下:
template<class T, class Size=decltype(elems(std::declval<T const&>()))>
bool operator<( T const& lhs, T const& rhs ) {
return auto_tie( Size{}, lhs ) < auto_tie( Size{}, rhs );
}
你已经完成了。
测试代码:
foo f0{1}, f1{2};
bar b0{1,2}, b1{-7, -3};
std::cout << (f0<f1) << (f1<f0) << (f0<f0) << "\n";
std::cout << (b0<b1) << (b1<b0) << (b0<b0) << "\n";
要比这更进一步,需要编写第三方工具或等待C ++的反射扩展,可能是在C ++ 20或23中。
如果您的elems
错误,我相信auto_tie
中的结构化绑定代码会产生错误。
答案 2 :(得分:0)
看起来最好的方法是编写一个生成器,它将生成带有bool运算符的.h和.cpp&lt;对于此头文件中的所有类型。然后将此项目作为预构建步骤添加到main。
它看起来不是一个好的解决方案,但它允许避免手写代码重复,并将支持添加/删除新的结构/字段。所以我找不到更好的方法。