Вы можете использовать универсальные указатели на элементы для доступа к нему.
Сначала определите ваших членов в пространстве имен:
namespace universal {
template<class T, unsigned int idx=0> struct member_ptr; // TODO
template<auto const*...> struct packed_struct; // TODO
template<auto const*...> struct unpacked_struct; // TODO
template<class...Ts> using variant=std::variant<Ts...>;
template<class...Ts> struct mutable_pointer:std::variant<Ts*...>{/*TODO*/};
template<class...Ts> using const_pointer = mutable_ptr<Ts const...>;
}
namespace Foo {
universal::member_ptr<int16_t> first;
universal::member_ptr<int8_t> second;
using packed = universal::packed_struct< &first, &second >;
using unpacked = universal::unpacked_struct< &first, &second >;
using either = universal::variant<packed, unpacked>;
using either_cptr = universal::const_pointer<packed, unpacked>;
using either_mptr = universal::mutable_pointer<packed, unpacked>;
}
тогда вы можете сделать:
void receivePacketFromNetwork( Foo::either_mptr ptr ) {
assert(ptr);
ptr->*Foo::first = 7;
ptr->*Foo::second = 3;
}
и он работает на обоих типах структуры.
Запись материала в namespace universal
не просто , но это не невозможно.
Основная идея - перегрузить operator->*
.
template<class T>
struct member_ptr {
template<class...Ts,
std::enable_if_t< supports<Ts>() && ..., bool> = true
>
T& operator->*( std::variant<Ts...>& lhs, member_ptr const& self ) {
return std::visit(
[&self]( auto&& lhs )->T&{ return lhs->*self; },
lhs
);
}
template<class U>
constexpr static bool supports(); //TODO
};
template<auto const* a, auto const* b, auto const*... bs>
struct unpacked_struct<a, b, bs...>:
unpacked_struct<a>,
unpacked_struct<b, bs...>
{
using unpacked_struct<a>::operator->*;
using unpacked_struct<b, bs...>::operator->*;
};
template<class T, , unsigned int idx, member_ptr<T, idx> const* a>
struct unpacked_struct<a> {
T data;
T& operator->*( member_ptr<T, idx> const& ) & {
return data;
}
T&& operator->*( member_ptr<T, idx> const& ) && {
return std::move(data);
}
T const& operator->*( member_ptr<T, idx> const& ) const& {
return data;
}
T const&& operator->*( member_ptr<T, idx> const& ) const&& {
return std::move(data);
}
};
и т.д.