If I have a constructor with n parameters such that any argument to that can be an rvalue and lvalue. Is it possible to do support this with move semantics for the rvalues witho
Take the following code ideone link.
#include
class A
{
public:
A() : i(0) {}
A(const A& a) : i(a.i) { std::cout << "Copy A" << std::endl; }
A(A&& a) : i(a.i) { std::cout << "Move A" << std::endl; }
int i;
};
template
class B1
{
public:
template
B1(T1&& x1_, T2&& x2_) : x1(std::forward(x1_)), x2(std::forward(x2_)) {}
B1(const B1& x) : x1(x.x1), x2(x.x2) { std::cout << "Copy B1" << std::endl; }
B1(B1&& x) : x1(std::move(x.x1)), x2(std::move(x.x2)) { std::cout << "Move B1" << std::endl; }
private:
T x1;
T x2;
};
template
class B2
{
public:
B2(T x1_, T x2_) : x1(std::move(x1_)), x2(std::move(x2_)) {}
B2(const B2& x) : x1(x.x1), x2(x.x2) { std::cout << "Copy B2" << std::endl; }
B2(B2&& x) : x1(std::move(x.x1)), x2(std::move(x.x2)) { std::cout << "Move B2" << std::endl; }
private:
T x1;
T x2;
};
A&& inc_a(A&& a) { ++a.i; return static_cast(a); }
A inc_a(const A& a) { A a1 = a; ++a1.i; return a1; }
int main()
{
A a1;
A a2;
std::cout << "1" << std::endl;
B1 b1(a1,a2);
std::cout << "2" << std::endl;
B1 b2(a1,A());
std::cout << "3" << std::endl;
B1 b3(A(),a2);
std::cout << "4" << std::endl;
B1 b4(A(),A());
std::cout << "5" << std::endl;
B2 b5(a1,a2);
std::cout << "6" << std::endl;
B2 b6(a1,A());
std::cout << "7" << std::endl;
B2 b7(A(),a2);
std::cout << "8" << std::endl;
B2 b8(A(),A());
std::cout << "9" << std::endl;
std::cout << std::endl;
std::cout << "11" << std::endl;
B1 b11(a1,a2);
std::cout << "12" << std::endl;
B1 b12(a1,inc_a(A()));
std::cout << "13" << std::endl;
B1 b13(inc_a(A()),a2);
std::cout << "14" << std::endl;
B1 b14(inc_a(A()),inc_a(A()));
std::cout << "15" << std::endl;
B2 b15(a1,a2);
std::cout << "16" << std::endl;
B2 b16(a1,inc_a(A()));
std::cout << "17" << std::endl;
B2 b17(inc_a(A()),a2);
std::cout << "18" << std::endl;
B2 b18(inc_a(A()),inc_a(A()));
std::cout << "19" << std::endl;
}
Which outputs the following:
1
Copy A
Copy A
2
Copy A
Move A
3
Move A
Copy A
4
5
Copy A
Copy A
Move A
Move A
6
Copy A
Move A
Move A
7
Copy A
Move A
Move A
8
9
11
Copy A
Copy A
12
Copy A
Move A
13
Move A
Copy A
14
Move A
Move A
15
Copy A
Copy A
Move A
Move A
16
Move A
Copy A
Move A
Move A
17
Copy A
Move A
Move A
Move A
18
Move A
Move A
Move A
Move A
19
As can be seen, the pass by value approach in B2 causes extra move for each argument in all cases except for when the argument is a prvalue.
If you want best performance, I suggest the template approach in B1. This way you have effectively have separate code for the copy and move cases, and hence only a single copy or a single move required. In the pass by value approach, at least two move/copies are required, except for the prvalue case where the compiler can construct the value in the place of the argument, in which as only one move is required.