C ++での一般的な構造体を比較するには?

フレドリックEnetorp:

私は一般的な方法で構造体を比較したいと私は(私は実際のソースを共有するので、必要に応じて詳細を求めることができない)このような何かをやりました:

template<typename Data>
bool structCmp(Data data1, Data data2)
{
  void* dataStart1 = (std::uint8_t*)&data1;
  void* dataStart2 = (std::uint8_t*)&data2;
  return memcmp(dataStart1, dataStart2, sizeof(Data)) == 0;
}

時にはそれが2つの構造体のインスタンスが同一の部材(私はEclipseのデバッガでチェックした)を持っているにもかかわらずfalseを返すことを除いてこれは主に、意図したとおりに動作します。いくつかの検索後、私はそれが発見されたmemcmp構造体が埋められている使用のために失敗する可能性があります。

パディングに無関心だメモリを比較し、より適切な方法はありますか?私が使用し、構造体を変更することはできませんよ(私が使用しているAPIの彼らはしている部分)と、使用される多くの異なった構造体は、いくつかの異なるメンバーを有するので、(私の知る限りでは)一般的な方法で個別に比較することはできません。

編集:私は残念ながらC ++ 11で立ち往生しています。この先に言及したはずです...

Yakk - アダムNevraumont:

いいえ、memcmpこれを行うには適していません。そして、C ++での反射が、この時点でこれを行うには不十分である(そこサポート反射十分に強いが、すでにこれを実行するための実験コンパイラということになるだろう、と持っているかもしれない、あなたは必要な機能します)。

内蔵の反射がなければ、あなたの問題を解決する最も簡単な方法は、いくつかの手動反射を行うことです。

これを取る:

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 );
}

以下のための、次のようになります。

template<class S>
bool are_equal( S const& lhs, S const& rhs ) {
  return as_tie(lhs) == as_tie(rhs);
}

かなりまともな仕事をしていません。

私たちは、仕事のビットが再帰的であることを、このプロセスを拡張することができます。代わりにネクタイを比較すること、テンプレートに包まれた各要素を比較し、そのテンプレートのoperator==再帰的(の要素ラップこのルールを適用するas_tie要素が既に作業を持っていない限り、比較すると)==、およびハンドルアレイ。

これは、ライブラリのビットが必要になります(コードの100ish行を?)一緒に手動ごとのメンバー「反射」1ビットのデータを書き込むことで。あなたが持っている構造体の数が限られている場合は、手動ごとの構造体のコードを記述する方が簡単かもしれません。


取得する方法は、おそらくあります。

REFLECT( some_struct, x, d1, d2, c )

生成するas_tie恐ろしいマクロを使用して構造を。しかし、as_tieシンプルで十分です。ではの繰り返しは迷惑です。これは便利です。

#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 ) )

refl_tie(配列)(完全再帰もサポート・アレイ・オブ・アレイ):

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) )

それはそれを介して再帰をサポートしていません。

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=30164&siteId=1