아니요, memcmp
이 작업에는 적합하지 않습니다. 그리고 C ++의 리플렉션은이 시점 에서이 작업을 수행하기에 충분하지 않습니다 (이미 수행 할 수있을만큼 강한 리플렉션을 지원하는 실험용 컴파일러가 있으며 c ++ 23 에는 필요한 기능이있을 수 있음).
내장 리플렉션이 없으면 문제를 해결하는 가장 쉬운 방법은 수동 리플렉션을 수행하는 것입니다.
이것을 가지고 :
struct some_struct {
int x;
double d1, d2;
char c;
};
우리는 최소한의 작업을 수행하여 두 가지를 비교할 수 있습니다.
우리가 가지고 있다면 :
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) (완전히 재귀 적이며 배열 배열을 지원합니다) :
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) )
그러나 그것은 그것을 통한 재귀를 지원하지 않습니다.