Consider these classes:
#include
#include
class A
{
std::string test;
public:
A (std::string t) : test(std::move(t))
The "by-value" approach is an option. It is not as optimal as what you have, but only requires one overload:
class B
{
A a;
public:
B (A _a) : a(move(_a)) {}
};
The cost is 1 extra move construction for both lvalues and xvalues, but this is still optimal for prvalues (1 move). An "xvalue" is an lvalue that has been cast to rvalue using std::move.
You could also try a "perfect forwarding" solution:
class B
{
A a;
public:
template ::value
>::type>
B (T&& _a) : a(std::forward(_a)) {}
};
This will get you back to the optimal number of copy/move constructions. But you should constrain the template constructor such that it is not overly generic. You might prefer to use is_convertible instead of is_constructible as I've done above. This is also a single constructor solution, but as you add parameters, your constraint gets increasingly complicated.
Note: The reason the constraint is necessary above is because without, clients of B
will get the wrong answer when they query std::is_constructible::value
. It will mistakenly answer true without a proper constraint on B
.
I would say that none of these solutions is always better than the others. There are engineering tradeoffs to be made here.