不,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
进行比较),除非该元素已经有一个工作==
,并处理数组。
这将需要一些库(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) (完全递归,甚至支持arrays-of-arrays):
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
of 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) )
但这不支持通过它进行递归。