Non, memcmp
ne convient pas pour cela. Et la réflexion en C ++ est insuffisante pour ce faire à ce stade (il y aura des compilateurs expérimentaux qui prennent en charge la réflexion suffisamment forte pour le faire déjà, et c ++ 23 pourrait avoir les fonctionnalités dont vous avez besoin).
Sans réflexion intégrée, la façon la plus simple de résoudre votre problème consiste à effectuer une réflexion manuelle.
Prends ça:
struct some_struct {
int x;
double d1, d2;
char c;
};
nous voulons faire le minimum de travail afin de pouvoir comparer deux d'entre eux.
Si nous avons:
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 );
}
pour c ++ 11 , alors:
template<class S>
bool are_equal( S const& lhs, S const& rhs ) {
return as_tie(lhs) == as_tie(rhs);
}
fait un travail assez décent.
Nous pouvons étendre ce processus pour qu'il soit récursif avec un peu de travail; au lieu de comparer les liens, comparez chaque élément encapsulé dans un modèle, et ce modèle operator==
applique récursivement cette règle (encapsulant l'élément as_tie
pour comparer) à moins que l'élément n'ait déjà un travail ==
et gère les tableaux.
Cela nécessitera un peu de bibliothèque (100 lignes de code?) Avec l'écriture d'un peu de données de «réflexion» manuelles par membre. Si le nombre de structures que vous avez est limité, il pourrait être plus facile d'écrire manuellement du code par structure.
Il existe probablement des moyens
REFLECT( some_struct, x, d1, d2, c )
pour générer la as_tie
structure en utilisant d'horribles macros. Mais as_tie
c'est assez simple. En c ++ 11, la répétition est ennuyeuse; c'est utile:
#define RETURNS(...) \
noexcept(noexcept(__VA_ARGS__)) \
-> decltype(__VA_ARGS__) \
{ return __VA_ARGS__; }
dans cette situation et bien d'autres. Avec RETURNS
, écrire as_tie
c'est:
auto as_tie(some_struct const& s)
RETURNS( std::tie( s.x, s.d1, s.d2, s.c ) )
supprimer la répétition.
Voici un coup de couteau pour le rendre récursif:
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) (entièrement récursif, prend même en charge les tableaux de tableaux):
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>{} ) )
Exemple en direct .
Ici, j'utilise un std::array
de refl_tie
. C'est beaucoup plus rapide que mon précédent tuple de refl_tie au moment de la compilation.
Aussi
template<class T,
typename std::enable_if< !std::is_class<T>{}, bool>::type = true
>
auto refl_tie( T const& t )
RETURNS(std::cref(t))
utiliser std::cref
ici au lieu de std::tie
pourrait économiser sur la surcharge au moment de la compilation, comme cref
c'est une classe beaucoup plus simple que tuple
.
Enfin, vous devez ajouter
template<class T, std::size_t N, class...Ts>
auto refl_tie( T(&t)[N], Ts&&... ) = delete;
ce qui empêchera les membres du tableau de se décomposer en pointeurs et de retomber sur l'égalité du pointeur (ce que vous ne voulez probablement pas des tableaux).
Sans cela, si vous passez un tableau à une structure non réfléchie, il retombe sur une structure pointeur vers non réfléchie refl_tie
, qui fonctionne et renvoie un non-sens.
Avec cela, vous vous retrouvez avec une erreur de compilation.
La prise en charge de la récursivité à travers les types de bibliothèques est délicate. Vous pourriez std::tie
les:
template<class T, class A>
auto refl_tie( std::vector<T, A> const& v )
RETURNS( std::tie(v) )
mais cela ne prend pas en charge la récursivité à travers elle.