Нет, 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
для сравнения), если элемент уже не имеет работающего ==
и не обрабатывает массивы.
Для этого потребуется немного библиотеки (100i sh строк кода?) Вместе с записью небольшого количества ручных данных "отражения" для каждого члена. Если количество имеющихся у вас структур ограничено, возможно, было бы проще написать код для каждой структуры вручную.
Возможно, есть способы получить
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_t ie (массив) (полностью рекурсивный, даже поддерживает массивы массивов):
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_t ie во время компиляции.
Также
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) )
, но это не поддерживает рекурсию через него.