不,memcmp
不适合这样做。在这一点上,C ++中的反射还不足以做到这一点(将会有实验性的编译器支持足够强大的反射功能来执行此操作,而c ++ 23可能具有所需的功能)。
如果没有内置反射,解决问题的最简单方法就是进行一些手动反射。
拿着它:
struct some_struct {
int x;
double d1, d2;
char c;
};
我们希望进行最少的工作,因此我们可以比较其中的两个。
如果我们有:
auto as_tie(some_struct const& s){
return std::tie( s.x, s.d1, s.d2, s.c );
}
要么
auto as_tie(some_struct const& s)
-> decltype(std::tie( s.x, s.d1, s.d2, s.c ))
{
return std::tie( s.x, s.d1, s.d2, s.c );
}
对于c ++ 11,则:
template<class S>
bool are_equal( S const& lhs, S const& rhs ) {
return as_tie(lhs) == as_tie(rhs);
}
做得不错。
我们可以通过一些工作来将此过程扩展为递归的。而不是比较关系,而是比较包装在模板中的每个元素,并且该模板将operator==
递归地应用此规则(将元素包装as_tie
以进行比较),除非该元素已经具有work ==
并处理数组。
这将需要一些库(100行代码?)以及编写一些手动的每个成员的“反射”数据。如果您拥有的结构数量有限,则手动编写每个结构的代码可能会更容易。
可能有办法
REFLECT( some_struct, x, d1, d2, c )
as_tie
使用可怕的宏来生成结构。但是as_tie
很简单。在c ++ 11中,重复很烦人。这很有用:
#define RETURNS(...) \
noexcept(noexcept(__VA_ARGS__)) \
-> decltype(__VA_ARGS__) \
{ return __VA_ARGS__; }
在这种情况下,还有许多其他情况。使用RETURNS
,写作as_tie
是:
auto as_tie(some_struct const& s)
RETURNS( std::tie( s.x, s.d1, s.d2, s.c ) )
删除重复。
这是递归的一个障碍:
template<class T,
typename std::enable_if< !std::is_class<T>{}, bool>::type = true
>
auto refl_tie( T const& t )
RETURNS(std::tie(t))
template<class...Ts,
typename std::enable_if< (sizeof...(Ts) > 1), bool>::type = true
>
auto refl_tie( Ts const&... ts )
RETURNS(std::make_tuple(refl_tie(ts)...))
template<class T, std::size_t N>
auto refl_tie( T const(&t)[N] ) {
// lots of work in C++11 to support this case, todo.
// in C++17 I could just make a tie of each of the N elements of the array?
// in C++11 I might write a custom struct that supports an array
// reference/pointer of fixed size and implements =, ==, !=, <, etc.
}
struct foo {
int x;
};
struct bar {
foo f1, f2;
};
auto refl_tie( foo const& s )
RETURNS( refl_tie( s.x ) )
auto refl_tie( bar const& s )
RETURNS( refl_tie( s.f1, s.f2 ) )
c ++ 17 refl_tie(array)(完全递归,甚至支持数组数组):
template<class T, std::size_t N, std::size_t...Is>
auto array_refl( T const(&t)[N], std::index_sequence<Is...> )
RETURNS( std::array<decltype( refl_tie(t[0]) ), N>{ refl_tie( t[Is] )... } )
template<class T, std::size_t N>
auto refl_tie( T(&t)[N] )
RETURNS( array_refl( t, std::make_index_sequence<N>{} ) )
现场例子。
在这里我使用std::array
的refl_tie
。这比我在编译时以前的refl_tie元组要快得多。
也
template<class T,
typename std::enable_if< !std::is_class<T>{}, bool>::type = true
>
auto refl_tie( T const& t )
RETURNS(std::cref(t))
使用std::cref
此处而不是std::tie
可以节省编译时的开销,因为这cref
是比类更简单的类tuple
。
最后,您应该添加
template<class T, std::size_t N, class...Ts>
auto refl_tie( T(&t)[N], Ts&&... ) = delete;
这将防止数组成员退化为指针,而后退到指针相等(您可能不需要数组)。
没有这个,如果您将数组传递给未反射的结构,它就会退回到指针指向未反射的结构上refl_tie
,该结构可以工作并返回无意义。
这样,您最终会遇到编译时错误。
通过库类型支持递归比较棘手。你可以std::tie
他们:
template<class T, class A>
auto refl_tie( std::vector<T, A> const& v )
RETURNS( std::tie(v) )
但这不支持通过它进行递归。