问题
I'm trying to understand rvalue
references. I have seen how they are used in constructors, with things like std::move
and std::forward
, but I still don't understand why this doesn't work:
void func(string&& str)
{
cout << str << endl;
}
int main(int argc, char* argv[])
{
string s("string");
func(s);
}
And this does:
template<typename T>
void func(T&& str)
{
cout << str << endl;
}
int main(int argc, char* argv[])
{
string s("string");
func(s);
}
Why does it work with the function template version?
回答1:
Like @Peter said, the type of T
is deduced as string&
, and C++’s reference-collapsing rule says:
T& & ⇒ T& // from C++98
T&& & ⇒ T& // new for C++0x
T& && ⇒ T& // new for C++0x
T&& && ⇒ T&& // new for C++0x
So func
’s instantiation is actually:
void func(string& str)
And it works.
回答2:
Some formal explanation in addition to @songyuanyao's answer:
N4296::14.8.2.1 [temp.deduct.call]
:
Template argument deduction is done by comparing each function template parameter type (call it P) with the type of the corresponding argument of the call (call it A) as described below.
N4296::14.8.2.1/3 [temp.deduct.call]
:
A forwarding reference is an rvalue reference to a cv-unqualified template parameter. If P is a forwarding reference and the argument is an lvalue, the type “lvalue reference to A” is used in place of A for type deduction.
The Standard also provides the following example:
template <class T> int f(T&& heisenreference);
template <class T> int g(const T&&);
int i;
int n1 = f(i); // calls f<int&>(int&)
int n2 = f(0); // calls f<int>(int&&)
int n3 = g(i); // error: would call g<int>(const int&&)
That's exactly your case.
回答3:
Because inside of a template &&
has a different meaning, it's called universal reference.
a template function with a &&
parameter (unversal reference) means the parmeter can be used as reference or rvalue-reference.
In your case the template is deduced as string&
and that's why it works.
To work with the raw function you have to do this:
void func(string&& str)
{
cout << str << endl;
}
int main(int argc, char* argv[])
{
string s("string");
func(std::move(s)); // move the string
func(std::string("string")); // this is an rvalue and it is fine
}
A complete explanation about universal references can be found here: https://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers
来源:https://stackoverflow.com/questions/30339922/c-rvalue-references-in-function-parameters