Tidak, memcmp
tidak cocok untuk melakukan ini. Dan refleksi dalam C ++ tidak cukup untuk melakukan ini pada saat ini (akan ada kompiler eksperimental yang mendukung refleksi yang cukup kuat untuk melakukan ini, dan c ++ 23 mungkin memiliki fitur yang Anda butuhkan).
Tanpa refleksi bawaan, cara termudah untuk menyelesaikan masalah Anda adalah dengan melakukan refleksi manual.
Ambil ini:
struct some_struct {
int x;
double d1, d2;
char c;
};
kami ingin melakukan jumlah pekerjaan minimal sehingga kami dapat membandingkan dua di antaranya.
Jika kita memiliki:
auto as_tie(some_struct const& s){
return std::tie( s.x, s.d1, s.d2, s.c );
}
atau
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 );
}
untuk c ++ 11 , maka:
template<class S>
bool are_equal( S const& lhs, S const& rhs ) {
return as_tie(lhs) == as_tie(rhs);
}
melakukan pekerjaan yang cukup baik.
Kita dapat memperluas proses ini menjadi rekursif dengan sedikit pekerjaan; alih-alih membandingkan ikatan, bandingkan setiap elemen yang dibungkus dengan templat, dan templat itu operator==
secara rekursif menerapkan aturan ini (membungkus elemen as_tie
untuk membandingkan) kecuali elemen tersebut sudah memiliki kerja==
, dan menangani array.
Ini akan membutuhkan sedikit perpustakaan (100ish baris kode?) Bersama dengan menulis sedikit data "refleksi" manual per anggota. Jika jumlah struct yang Anda miliki terbatas, mungkin lebih mudah untuk menulis kode per-struct secara manual.
Mungkin ada cara untuk mendapatkannya
REFLECT( some_struct, x, d1, d2, c )
untuk menghasilkan as_tie
struktur menggunakan macro yang mengerikan. Tetapi as_tie
cukup sederhana. Dalam c ++ 11 pengulangan itu menjengkelkan; ini berguna:
#define RETURNS(...) \
noexcept(noexcept(__VA_ARGS__)) \
-> decltype(__VA_ARGS__) \
{ return __VA_ARGS__; }
dalam situasi ini dan banyak lainnya. Dengan RETURNS
, menulis as_tie
adalah:
auto as_tie(some_struct const& s)
RETURNS( std::tie( s.x, s.d1, s.d2, s.c ) )
menghapus pengulangan.
Berikut ini adalah cara membuatnya rekursif:
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) (sepenuhnya rekursif, bahkan mendukung array-of-array):
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>{} ) )
Contoh langsung .
Di sini saya menggunakan std::array
dari refl_tie
. Ini jauh lebih cepat daripada tuple refl_tie saya sebelumnya pada waktu kompilasi.
Juga
template<class T,
typename std::enable_if< !std::is_class<T>{}, bool>::type = true
>
auto refl_tie( T const& t )
RETURNS(std::cref(t))
menggunakan di std::cref
sini bukannya std::tie
bisa menghemat waktu kompilasi, seperti cref
kelas yang jauh lebih sederhana daripada tuple
.
Akhirnya, Anda harus menambahkan
template<class T, std::size_t N, class...Ts>
auto refl_tie( T(&t)[N], Ts&&... ) = delete;
yang akan mencegah anggota array dari peluruhan ke pointer dan jatuh kembali pada pointer-kesetaraan (yang Anda mungkin tidak inginkan dari array).
Tanpa ini, jika Anda meneruskan array ke struct yang tidak direfleksikan, ia jatuh kembali ke pointer ke struct yang tidak direfleksikan refl_tie
, yang berfungsi dan mengembalikan omong kosong.
Dengan ini, Anda berakhir dengan kesalahan waktu kompilasi.
Dukungan untuk rekursi melalui tipe perpustakaan cukup rumit. Anda dapat std::tie
melakukannya:
template<class T, class A>
auto refl_tie( std::vector<T, A> const& v )
RETURNS( std::tie(v) )
tetapi itu tidak mendukung rekursi melalui itu.