可以编写一个通用函数,该函数可以比较不同类的对象,而这些函数的对象不定义
operator==
,例如:
template<typename T>
bool Compare(T obj1, T obj2) {
...?...
}
class Class1 {
int i;
int *pi;
};
class Class2 {
char c;
char *pc;
std::string *ps;
};
Class1 a1, b1;
Initialise...
bool c1 = Compare(a1, b1);
Class2 a2, b2;
Initialise...
bool c2 = Compare(a2, b2);
在何处也比较了指向的值,即::
*a1.pi == *b1.pi
如果我比较了两个对象的内存块,我会得到类似的东西:
a1.pi == b1.pi
韦尔,首先是第一件事。
正如在原始问题的评论中所说的那样,我不确定这个问题是出于多种原因而引起的(主要原因是操作员==是正确的方法)。因此,我们不能像在c#或java中那样进行
a.GetFields()
循环。 ,但是,我们仍然需要一种方法来获取字段并以某种方式“枚举”它们。由于C ++是强烈键入的,因此我们还需要字段类型,并且不能像在JavaScript中那样依赖某些“运行时魔法”。 意味着我们需要一个类型列表。存在许多实现,但我们只需要基本功能,所以这是最愚蠢的可能版本:
#pragma once
#include <cstdint>
template <typename... Ts>
struct type_list;
namespace internal {
template <size_t i, typename T, typename... Ts>
struct type_at {
static_assert(i < sizeof...(Ts) + 1, "index out of range");
using type = typename type_at<i - 1, Ts...>::type;
};
template <typename T, typename... Ts> struct type_at<0, T, Ts...> {
using type = T;
};
template <size_t i, typename... Ts>
using type_at_t = typename type_at<i, Ts...>::type;
}
template <typename... Ts>
struct type_list {
static constexpr size_t length = sizeof...(Ts);
template <size_t index>
using at = internal::type_at_t<index, Ts...>;
};
template <>
struct type_list<> {
static constexpr size_t length = 0;
};
auto get_field(int x)
,因为不同指数的返回类型是不同的。 llet用不透明的指针包裹了所有内容(void*):
template<typename FieldType>
union opaque_field {
FieldType x;
void* opaque;
};
从一个简单的类开始:
class A {
friend struct GetFields<A>; // only addition to make in your business code
private:
int _x;
double _y;
A* _next;
A(int x, int y, A* next = nullptr) {
this->_x = x;
this->_y = y;
this->_next = next;
}
};
template<typename T>
struct GetFields;
template<typename T>
struct FieldTypes;
template<>
struct FieldTypes<A> {
using type = type_list<int, double, A*>;
};
template<>
struct GetFields<A> {
static void* get_field(const A& a, size_t index) {
switch (index) {
case 0:
return opaque_field<int> { a._x }.opaque;
case 1:
return opaque_field<double> { a._y }.opaque;
case 2:
return opaque_field<A*> { a._next }.opaque;
default:
return nullptr;
// do something (throw ?)
}
}
};
必须针对所有“可比较”类型(而不是标量 /指示 /算术)实现这种丑陋的逻辑。同样,为什么不只是写一个好的旧操作员==,但是让我们继续玩C ++。
模板比较
完成后,我们无法实现模板比较以下属性: 如果参数不为同一类型,则返回false Compare算术和枚举值直接
指示指示可以比较内容(最好不要使用C,例如内存分配)中复合类型(结构或类),一一比较字段。
template<typename T1, typename T2, typename E = void>
struct compare_helper {
static bool compare(const T1& x, const T2& y) {
return false;
}
};
template<typename T>
struct compare_helper<T, T, std::enable_if_t<
(std::is_enum_v<T> || std::is_arithmetic_v<T>) && !std::is_pointer_v<T>>> {
static bool compare(const T& x, const T& y) {
return x == y;
}
};
template<typename T>
struct compare_helper<T*, T*> {
static bool compare(T* x, T* y) {
if (x == nullptr && y == nullptr) {
return true;
}
if ((x == nullptr && y != nullptr) || (y == nullptr && x != nullptr)) {
return false;
}
return compare_helper<T, T>::compare(*x, *y);
}
};
template<typename T>
struct compare_helper<T, T, std::enable_if_t<
(!std::is_pointer_v<T> && !std::is_enum_v<T> && !std::is_arithmetic_v<T>)
>> {
// oh the beautiful compile time loop because we can't do a for loop
template<size_t index, size_t stop>
struct inner {
using field_type = typename FieldTypes<T>::type::template at<index>;
static bool func(const T& x, const T& y) {
field_type left = opaque_field<field_type>{ .opaque = GetFields<A>::get_field(x, index) }.x;
field_type right = opaque_field<field_type>{ .opaque = GetFields<A>::get_field(y, index) }.x;
return compare_helper<field_type, field_type>::compare(left, right) && inner<index + 1, stop>::func(x, y);
}
};
template<size_t stop>
struct inner<stop, stop> {
static bool func(const T& x, const T& y) {
return true;
}
};
static bool compare(const T& x, const T& y) {
return inner<0, FieldTypes<T>::type::length>::func(x, y);
}
};
// final wrap in a template function for ease of use
template<typename T1, typename T2>
bool Compare(const T1& x, const T2& y) {
return compare_helper<T1, T2>::compare(x, y);
}
,然后使用非常简单:
int main() {
A* a = new A(1, 2);
A* b = new A(1, 2, a);
A* c = new A(1, 2, a);
printf("%d\n", Compare(a, b));
printf("%d\n", Compare(b, c));
return 0;
}