为比较“深度”中不同类的对象的函数?

问题描述 投票:0回答:1

可以编写一个通用函数,该函数可以比较不同类的对象,而这些函数的对象不定义

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++ templates generics
1个回答
0
投票

韦尔,首先是第一件事。

正如在原始问题的评论中所说的那样,我不确定这个问题是出于多种原因而引起的(主要原因是操作员==是正确的方法)。
  • 我不建议在下面使用代码
  • 我不建议尝试修复下面的代码 - 只需阅读(或者)并将其删除)
  • ,无论如何,这是想出一些有趣的模板的机会,所以我忍不住要抗拒。 C++没有反射

因此,我们不能像在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; };

,然后我们需要一种在“可比类”中获取字段的方法。这意味着我们的课程将获得返回ITH字段的函数。但是,同样,C ++是强烈键入的,因此我们不能拥有

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; }
    complete示例
  • HERHERINED
最新问题
© www.soinside.com 2019 - 2024. All rights reserved.