Try running this test program :
#include <iostream> class A { public: A() { std::cout << "empty constructor" << std::endl; } A(const A &a) { std::cout << "copy constructor" << std::endl; } A(A &&a) { std::cout << "move constructor" << std::endl; } ~A() { std::cout << "destructor" << std::endl; } A &operator=(const A &o) { std::cout << "copy assignment" << std::endl; return *this; } A &operator=(A &&o) { std::cout << "move assignment" << std::endl; return *this; } }; A outside; template <typename U> void bar(U &&a) { outside = std::forward<U>(a); } void foo(A &&a) { bar(a); } int main(int argc, char *argv[]) { foo(A()); return 0; } On my compiler, I think GCC 4.4.1, the output is:
empty constructor empty constructor copy assignment // what?? destructor destructor In my opinion the third line is strange. Why is outside copying a in bar instead of moving it? In other words,hy does foo use the bar(A &a) instantiation of bar instead of bar(A &&a)?
I should mention that this problem is easily fixable by changing foo to
template <typename U> void foo(U &&a) { bar(std::forward<U>(a)); } whereupon the move assignment operator is used instead.
In my code I have a lot of delegation methods and I'd hate to have to stick them all in a .h file and make templates for them. Is there another way of telling the compiler or making it understand that a is used as an rvalue in foo?
EDIT: A few people pointed out this change:
void foo(U &&a) { bar(std::move(a)); } I was too slow to indicate that I want foo to be able to accept both:
int main(int argc, char *argv[]) { foo(A()); return 0; } and
int main(int argc, char *argv[]) { A a; foo(a); return 0; } The suggested code will incorrectly steal, in the second case, a's resources in main where it should be used as a reference.
ainfoois an lvalue. You needbar(std::move(a));. I'm looking for a good duplicate.foo( (A&&)a )(which is what your version of g++ is doing), thenfoodoes not have the information about whether it was called with a temporary object or not; you have to either copy (bar(a)) or steal resources (bar(std::move(a))). The proper way to steal only from rvalues (without using a template) is to have a pair of overloadsvoid foo(A& a) { bar(a); } void foo(A&& a) { bar(std::move(a)); }template<typename T> void foo(T &&a) { bar(std::forward(a)); }because forwarding references can deduce reference types; but I guess you didn't do this because you could have just calledbarin the first place :)