いいえ、memcmp
これを行うには適していません。また、C ++でのリフレクションでは、現時点ではこれを行うには不十分です(これを行うのに十分なリフレクションをサポートする実験的なコンパイラがすでにあり、c ++ 23に必要な機能がある場合があります)。
組み込みのリフレクションがない場合、問題を解決する最も簡単な方法は、手動でリフレクションを行うことです。
これを取る:
struct some_struct {
int x;
double d1, d2;
char c;
};
これらの2つを比較できるように、最小限の作業を行います。
私たちが持っている場合:
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)(完全に再帰的、array-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
のを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) )
しかし、それはそれを介した再帰をサポートしていません。