Assuming a struct containing a number of variables:
struct A {
int a;
bool b;
string c;
};
Supposedly, I need to map them out to store in a single collection
auto ptr_= reinterpret_cast<UniversalType>(&A::a)
;
What would be the universal type to cast to and from a pointer to any of the members in order to emulate type erasure?
Can uintptr_t
be used for that?
PS. It's emebdded project with no RTTI support. So assumptions:
are wrong. It's the original problem existing with portability of pre-existing codebase. Dynamic dispatch is used in some cases and is used currently but it's manual (using function pointers) and ineffective. Compile-time dispatch is possible.
You may simply invent your own type erasure wrapper, like this:
class MemberPtr {
private:
struct AbstractMemberPtr {
virtual ~AbstractMemberPtr() = default;
};
template<typename R, typename T>
struct MemberPtrWrapper: AbstractMemberPtr {
R T::* ptr;
explicit MemberPtrWrapper(R T::* ptr) noexcept : ptr{ ptr } {}
R T::* operator*() const noexcept { return ptr; }
};
std::unique_ptr<AbstractMemberPtr> m_ptr;
public:
template<typename R, typename T>
MemberPtr(R T::* memberPtr): m_ptr{ std::make_unique<MemberPtrWrapper<R,T>>(memberPtr) }
{
}
template<typename R, typename T>
R T::* RawPtr() const {
if (const auto* const ptr = dynamic_cast<MemberPtrWrapper<R, T>*>(m_ptr.get())) {
return *(*ptr);
} else {
return nullptr;
}
}
};
In a collection it can be used like this:
std::vector<MemberPtr> ptrs;
ptrs.push_back(MemberPtr{&A::a});
ptrs.push_back(MemberPtr{&A::c});
And then extracted like this:
if (const auto strPtr = ptrs.back().RawPtr<std::string, A>()) {
A a;
a.*(strPtr) = "some string";
}
Alternatively (if you don't need to deduce all members automagically), you can simply use std::variant
:
using MembersVariant = std::variant<decltype(&A::a), decltype(&A::b), decltype(&A::c)>;
std::vector<MembersVariant> ptrs;
ptrs.emplace_back(&A::a);
ptrs.emplace_back(&A::b);
A a;
// Visitor is a helper utility class, which looks as follows:
// template<typename... T> struct Visitor : T... { using T::operator()...; };
std::visit(Visitor{
[&a](std::string A::* memberPtr) {
a.*memberPtr = "some string";
},
[&a](bool A::* memberPtr) {
a.*memberPtr = true;
},
[&a](int A::* memberPtr) {
a.*memberPtr = 2;
}
}, ptrs.back());