Нет, 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
достаточно просто. В с ++ 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) )
но это не поддерживает рекурсию через это.