If I have two classes D1 and D2 that both derive from class Base, and I want to construct a particular one based on say, a boolean variable, there are various well known techniques, eg use a factory, or use smart pointers.
For example,
std::unique_ptr<Base> b;
if (flag)
{
b.reset(new D1());
}
else
{
b.reset(new D2());
}
But this uses the heap for allocation, which is normally fine but I can think of times where it would be good to avoid the performance hit of a memory allocation.
I tried:
Base b = flag ? D1() : D2(); // doesn’t compile
Base& b = flag ? D1() : D2(); // doesn’t compile
Base&& b = flag ? D1() : D2(); // doesn’t compile
Base&& b = flag ? std::move(D1()) : std::move(D2()); // doesn’t compile
My intention is that D1 or D2 whichever is chosen is constructed on the stack, and its lifetime ends when b goes out of scope. Intuitively, I feel there should be a way to do it.
I played with lambda functions and found that this works:
Base&& b = [j]()->Base&&{
switch (j)
{
case 0:
return std::move(D1());
default:
return std::move(D2());
}
}();
Why it doesn’t suffer from the same issues as the others that do not compile I do not know. Further, it would only be suitable for classes that are inexpensive to copy, because despite my explicit request to use move, it does I think still call a copy constructor. But if I take away the std::move, I get a warning!
I feel this is closer to what i think should be possible but it still has some issues:
Is there a better way of doing this?
If you know all the types, you can use a Boost.Variant, as in:
class Manager
{
using variant_type = boost::variant<Derived1, Derived2>;
struct NameVisitor : boost::static_visitor<const char*>
{
template<typename T>
result_type operator()(T& t) const { return t.name(); }
};
public:
template<typename T>
explicit Manager(T t) : v_(std::move(t)) {}
template<typename T>
Manager& operator=(T t)
{ v_ = std::move(t); return *this; }
const char* name()
{ return boost::apply_visitor(NameVisitor(), v_); }
private:
variant_type v_;
};
Note: by using variant, you no longer need a base class or virtual functions.
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