I'm trying to avoid a rather complex inheritance chain for a set of plain old data structs, but I need to store them all in a vector + share ownership with the caller.
Struct A {};
Struct B {};
using TInstruction = std::variant<A, B>;
struct holder {
std::vector<std::shared_ptr<TInstruction>> items;
};
static holder h;
// Every individual TInstruction gets its own add function, for validation purposes
void add(std::shared_ptr<A> a) {
// Somehow add this to h, while still sharing ownership with the caller
// h.emplace_back(???)
}
int main() {
holder h;
auto a = std::make_unique<A>();
auto b = std::make_unique<B>();
add(a);
// add(b) // not implemented
}
I've had moderate (but annoyingly poor) success with the following changes to the original idea:
using TInstruction = std::variant<std::shared_ptr<A>, std::shared_ptr<B>>
add()
and use .lock()
to turn it into a std::shared_ptrI don't mind #2 (it seems to me that it might be the right way to do it), but keeping the shared_ptr inside the variant inside of "outside" of it leads to some very verbose code and pattern matching.
Is it possible to do this at all? I essentially want to change the type of the shared pointer, but still express the idea of shared ownership.
Instead of using variant
, you could take advantage of shared_ptr<void>
being able to hold a shared_ptr
to anything, as long as you keep track of the type it is holding yourself, as in:
// Generic typelist
template <typename...>
struct Types;
// Find the 0-based index of type T in Types<...>
template <typename, typename>
struct Index;
// T is the first type in Types<...>
template <typename T, typename... Us>
struct Index<T, Types<T, Us...>> : std::integral_constant<int, 0> {};
// T is not the first type in Types<...>
template <typename T, typename U, typename... Us>
struct Index<T, Types<U, Us...>>
: std::integral_constant<int, 1 + Index<T, Types<Us...>>()> {};
template <typename... Ts>
struct SharedPtrVariant {
template <typename T>
explicit SharedPtrVariant(std::shared_ptr<T> p)
: sp(std::move(p)), index(Index<T, Types<Ts...>>()) {}
template <typename T>
std::shared_ptr<T> get() const {
return std::static_pointer_cast<T>(
Index<T, Types<Ts...>>() == index ? sp : nullptr);
}
private:
std::shared_ptr<void> sp;
int index;
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With