C++,函数参数中的右值引用

C++, rvalue references in function parameters

我正在尝试理解 rvalue 参考资料。我已经看到它们是如何在构造函数中使用的,比如 std::movestd::forward,但我仍然不明白为什么这不起作用:

void func(string&& str)
{
    cout << str << endl;
}
int main(int argc, char* argv[])
{
    string s("string");
    func(s);
}

这确实是:

template<typename T>
void func(T&& str)
{
    cout << str << endl;
}
int main(int argc, char* argv[])
{
    string s("string");
    func(s);
}

为什么函数模板版可以使用?

正如@Peter所说,T的类型被推导为string&,C++的引用折叠规则说:

T& & ⇒ T& // from C++98
T&& & ⇒ T& // new for C++0x
T& && ⇒ T& // new for C++0x
T&& && ⇒ T&& // new for C++0x

所以func的实例化实际上是:

void func(string& str)

而且有效。

除了@songyuanyao 的回答外还有一些正式的解释:

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.

该标准还提供了以下示例:

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&&)

这正是你的情况。

因为模板内部 && 有不同的含义,它被称为 universal reference.

带有 && 参数的模板函数(通用引用)意味着该参数可以用作引用或右值引用。

在您的情况下,模板被推断为 string&,这就是它起作用的原因。

要使用原始函数,您必须这样做:

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
}

关于通用引用的完整解释可以在这里找到: https://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers