Hayır, memcmp
bunu yapmak uygun değildir. Ve C ++ 'da yansıma bu noktada bunu yapmak için yetersizdir (bunu yapmak için yeterince güçlü yansımayı destekleyen deneysel derleyiciler olacaktır ve c ++ 23 ihtiyacınız olan özelliklere sahip olabilir).
Yerleşik yansıma olmadan, sorununuzu çözmenin en kolay yolu bazı manuel yansımalar yapmaktır.
Bunu al:
struct some_struct {
int x;
double d1, d2;
char c;
};
bunlardan ikisini karşılaştırabilmemiz için minimum miktarda iş yapmak istiyoruz.
Eğer sahipsek:
auto as_tie(some_struct const& s){
return std::tie( s.x, s.d1, s.d2, s.c );
}
veya
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 );
}
için c ++ 11 , o zaman:
template<class S>
bool are_equal( S const& lhs, S const& rhs ) {
return as_tie(lhs) == as_tie(rhs);
}
oldukça iyi bir iş çıkarıyor.
Bu işlemi biraz çalışma ile özyinelemeli olarak genişletebiliriz; bağları karşılaştırmak yerine, bir şablona sarılmış her öğeyi karşılaştırın ve öğenin zaten çalışmadığı ve dizileri işlemediği sürece şablonun operator==
bu kuralı yinelemeli olarak uygular ( as_tie
karşılaştırmak için öğeyi ==
sarar).
Bu, bir üye başına "yansıma" verisi yazma ile birlikte bir kütüphane (100 satır kod?) Gerektirir. Sahip olduğunuz yapı sayısı sınırlıysa, yapı başına kodu manuel olarak yazmak daha kolay olabilir.
Muhtemelen almanın yolları var
REFLECT( some_struct, x, d1, d2, c )
as_tie
korkunç makrolar kullanarak yapı oluşturmak . Ama as_tie
yeterince basit. Olarak 11 c ++ tekrarlama rahatsız edici olduğu; bu kullanışlı:
#define RETURNS(...) \
noexcept(noexcept(__VA_ARGS__)) \
-> decltype(__VA_ARGS__) \
{ return __VA_ARGS__; }
bu durumda ve diğerleri. İle RETURNS
yazmak as_tie
:
auto as_tie(some_struct const& s)
RETURNS( std::tie( s.x, s.d1, s.d2, s.c ) )
tekrarın kaldırılması.
İşte özyinelemede bir bıçak:
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 (dizi) (tamamen özyinelemeli, dizilerin dizilerini bile destekler):
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>{} ) )
Canlı örnek .
Burada bir std::array
of kullanıyorum refl_tie
. Bu derleme zamanında önceki refl_tie grubumdan çok daha hızlı.
Ayrıca
template<class T,
typename std::enable_if< !std::is_class<T>{}, bool>::type = true
>
auto refl_tie( T const& t )
RETURNS(std::cref(t))
kullanarak std::cref
burada yerine std::tie
derleme zamanı yükü üzerinde kurtarabilecek olarak cref
çok daha basit bir sınıftır tuple
.
Son olarak,
template<class T, std::size_t N, class...Ts>
auto refl_tie( T(&t)[N], Ts&&... ) = delete;
bu da dizi üyelerinin işaretçilere bozulmasını ve işaretçi eşitliğine (muhtemelen dizilerden istemediğiniz) geri düşmesini önler.
Bu olmadan, bir diziyi yansıtılmamış bir yapıya geçirirseniz, bu işaretçi-yansıtılmamış yapıya refl_tie
geri döner ve bu da saçma çalışır ve geri döner.
Bununla derleme zamanı hatası elde edersiniz.
Kütüphane türleriyle özyineleme desteği zor. Bunları yapabilirsiniz std::tie
:
template<class T, class A>
auto refl_tie( std::vector<T, A> const& v )
RETURNS( std::tie(v) )
ancak bu özyinelemeyi desteklemez.