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.