Why in C++0x, the compiler chooses the generic move assignment over the specific one?
I have the following code:
#include <iostream>
using namespace std;
template <class T> class Foo {
public:
template <class U> void operator = (const U &u) {
cout << "generic copy assigment\n";
}
void operator = (const Foo<T> &f) {
cout << "specific copy assigment\n";
}
template <class U> void operator = (U &&u) {
cout << "generic move assigment\n";
}
void operator = (Foo<T> &&f) {
cout << "specific move assigme开发者_开发问答nt\n";
}
};
int main() {
Foo<int> i, j;
i = j;
return 0;
}
If this runs, it prints "generic move assignment", i.e. the compiler prefers the move over the copy. However, if I comment out the two move assignments:
template <class T> class Foo {
public:
template <class U> void operator = (const U &u) {
cout << "generic copy assigment\n";
}
void operator = (const Foo<T> &f) {
cout << "specific copy assigment\n";
}
};
the output is "specific copy assignment".
In other words, when the class is move-enabled, the generic move is selected over the specific one, whereas if the class is not move-enabled, the specific copy is selected over the generic one.
Is it a bug of Visual Studio 2010 or is this behavior defined in the c++0x specifications?
Your template is not a "generic move assignment". But it is a "perfect forwarder", except that in your case it doesn't forward. The rule in C++0x is that template argument deduction treats a parameter "T&&" specially: Lvalue arguments deduce T
to ArgType&
, and Rvalue arguments deduce it to ArgType
. That way, an lvalue of type ArgType
will yield to ultimate parameter type ArgType&
, and an Rvalue will ultimately yield to ArgType&&
.
In your case, the lvalue right hand side yields a deduced parameter type "Foo &", which perfectly well matches the lvalue argument.
The currently draft (n3126) forbids the compiler to use the template to perform the copy assignment (in a very confusingly worded paragraph), though. It depens on the resolution of issue 1080 whether that will change or not.
#include <iostream>
using namespace std;
template <class T> class Foo {
public:
template <class U> void operator = (const U &u) {
cout << "generic copy assigment\n";
}
void operator = (const Foo<T> &f) {
cout << "specific copy assigment\n";
}
template <class U> void operator = (U &&u) {
cout << "generic move assigment\n";
}
// void operator = (Foo<T> &&f) {
// cout << "specific move assigment\n";
// }
};
int main() {
Foo<int> i, j;
i = std::move(j);
return 0;
}
精彩评论