Não, memcmp
não é adequado para fazer isso. E a reflexão no C ++ é insuficiente para fazer isso neste momento (haverá compiladores experimentais que suportam a reflexão suficientemente forte para fazer isso, e o c ++ 23 pode ter os recursos necessários).
Sem reflexão interna, a maneira mais fácil de resolver seu problema é fazer uma reflexão manual.
Pegue isso:
struct some_struct {
int x;
double d1, d2;
char c;
};
queremos fazer a quantidade mínima de trabalho para comparar dois deles.
Se tiver-mos:
auto as_tie(some_struct const& s){
return std::tie( s.x, s.d1, s.d2, s.c );
}
ou
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 );
}
para c ++ 11 , então:
template<class S>
bool are_equal( S const& lhs, S const& rhs ) {
return as_tie(lhs) == as_tie(rhs);
}
faz um trabalho bastante decente.
Podemos estender esse processo para ser recursivo com um pouco de trabalho; em vez de comparar laços, compare cada elemento envolvido em um modelo e o modelo operator==
aplica recursivamente essa regra (envolvendo o elemento as_tie
para comparação), a menos que o elemento já tenha um funcionamento ==
e lida com matrizes.
Isso exigirá um pouco de uma biblioteca (100 linhas de código?), Juntamente com a gravação de um pouco de dados manuais de "reflexão" por membro. Se o número de estruturas que você possui é limitado, pode ser mais fácil escrever o código por estrutura manualmente.
Provavelmente existem maneiras de obter
REFLECT( some_struct, x, d1, d2, c )
para gerar a as_tie
estrutura usando macros horríveis. Mas as_tie
é bastante simples. Em c ++ 11, a repetição é irritante; isso é útil:
#define RETURNS(...) \
noexcept(noexcept(__VA_ARGS__)) \
-> decltype(__VA_ARGS__) \
{ return __VA_ARGS__; }
nesta situação e em muitas outras. Com RETURNS
, escrever as_tie
é:
auto as_tie(some_struct const& s)
RETURNS( std::tie( s.x, s.d1, s.d2, s.c ) )
removendo a repetição.
Aqui está uma facada em torná-lo recursivo:
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) (totalmente recursivo, até suporta matrizes de matrizes):
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>{} ) )
Exemplo ao vivo .
Aqui eu uso um std::array
dos refl_tie
. Isso é muito mais rápido que minha tupla anterior de refl_tie em tempo de compilação.
Além disso
template<class T,
typename std::enable_if< !std::is_class<T>{}, bool>::type = true
>
auto refl_tie( T const& t )
RETURNS(std::cref(t))
usar std::cref
aqui em vez de std::tie
poderia economizar em custos adicionais em tempo de compilação, como cref
é uma classe muito mais simples que tuple
.
Por fim, você deve adicionar
template<class T, std::size_t N, class...Ts>
auto refl_tie( T(&t)[N], Ts&&... ) = delete;
o que impedirá que os membros da matriz se deteriorem para ponteiros e retornem à igualdade de ponteiros (o que você provavelmente não deseja das matrizes).
Sem isso, se você passar uma matriz para uma estrutura não refletida, ela recai na estrutura ponteiro para não refletida refl_tie
, que funciona e retorna um disparate.
Com isso, você acaba com um erro em tempo de compilação.
O suporte à recursão através dos tipos de biblioteca é complicado. Você poderia std::tie
:
template<class T, class A>
auto refl_tie( std::vector<T, A> const& v )
RETURNS( std::tie(v) )
mas isso não suporta recursão por meio dele.