I have a std::variant
whose alternatives are all pointers.
class a {
public:
int* placeholder;
a(a& _copy) { /* Does a deep copy */ }
}
class b {
// For demonstrational purposes, identical to a.
}
int main() {
std::vector<std::variant<a*, b*>> instances = // initialise vector, guaranteed no nullptrs.
}
Now, for instance, if I want to push a deep copy of the first element to the back, I cannot simply do instances.push_back(instances[0])
, because that does a shallow copy of the vector
.
Of course, the obvious solution would be to check for all alternatives, then get_if
, create a copy, and return the copy. However, I think there has to be a better way. How should something as such be done?
I am also open to solutions that do not use variants.
As mentioned in comments, you can use std::visit
. I strongly suggest to use smart pointers.
#include <variant>
#include <memory>
#include <iostream>
int main() {
// init and print x
std::variant<std::unique_ptr<int>,std::unique_ptr<std::string>> x = std::make_unique<std::string>("foo");
auto print = [](const auto& x) { std::cout << *x << "\n";};
std::visit(print,x);
// make the copy
auto deep_copy = [](const auto& x) -> std::variant<std::unique_ptr<int>,std::unique_ptr<std::string>> {
return std::make_unique<std::remove_reference_t<decltype(*x)>>(*x);
// replace this creating a proper clone
};
auto y = std::visit(deep_copy,x);
std::visit(print,y);
// check that it actually is a deep copy
auto modify = [](auto& x) { *x += 'a';};
std::visit(modify,x);
std::visit(print,x);
std::visit(print,y);
}
foo
foo
fooa
foo
I'll leave it to you to modify the code in case each variant requires a different way to copy. The above is the simple case where all types can be handled by a templated lambda. For the case of actually requiring distinct branches for each variant I refer you to documentation (eg https://en.cppreference.com/w/cpp/utility/variant/visit). Most importantly (as pointed out by user17732522 in their comment), this std::make_unique<std::remove_reference_t<decltype(*x)>>(*x)
is the wrong way to copy a std::unique_ptr<Base>
managing a Derived
instance.