I want to store objects of different types in a std::set
and rely on std::set
's sorting to later access them by some key variable which is present in every type. To store different types I am using variant
.
In a first step I created the same base class but for writing the comparator I am struggling how to access the base. I have something like the following to cast to the shared base class from a variant object:
#include <variant>
#include <string>
struct Base {
int i;
};
struct A : public Base {
int j;
};
struct B : public Base {
std::string k;
};
int main() {
std::variant<A, B> v(A{{1}, 2});
// how to get the following without UB and statically (Base offset
// within variant should be known at compile time)
Base &b{*reinterpret_cast<Base *>(&std::get<A>(v))};
}
The code above will fail (throw exception) when v
does not contain an A
type object. But apart from that it be theoretically possible to cast such a variant to the base Base
because within the variant the data (where the different A
or B
objects are placed) is aligned from what I have read.
What is a clean way to do polymorphism for a variant in such a case where all used types share the same base class? I don't want to use visit
because it is dynamically dispatching, doing runtime case distinction on the variant's actual type index variable. I feel it should be possible to do this without such case distinction but I fear std::variant
does not support this.
Also I am wondering if it is UB if I do the cast manually. Maybe I can also somehow get the offset of the data storage at compile time and add it to the address of a variant object?
You might use std::visit
as any std::variant
:
Base& getBase(std::variant<A, B>& a_or_b)
{
return std::visit([](auto& elem) -> Base& { return elem; }, a_or_b);
}