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

时间:2015-05-20 03:47:16

标签: c++ c++11 templates rvalue-reference

我正在尝试理解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);
}

为什么它适用于功能模板版本?

3 个答案:

答案 0 :(得分:15)

就像@Peter所说,T的类型推断为string&,而C ++的引用折叠规则则说:

  

T&安培; &安培; ⇒T&amp; //来自C ++ 98
  T&安培;&安培; &安培; ⇒T&amp; // C ++ 0x的新增内容   T&安培; &安培;&安培; ⇒T&amp; // C ++ 0x的新增内容   T&安培;&安培; &安培;&安培; ⇒T&amp;&amp; // C ++ 0x的新内容

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

void func(string& str)

它有效。

答案 1 :(得分:6)

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

N4296::14.8.2.1 [temp.deduct.call]

  

通过比较每个函数来完成模板参数推导   模板参数类型(称之为P)与对应的类型   呼叫的参数(称之为A)如下所述。

N4296::14.8.2.1/3 [temp.deduct.call]

  

转发参考是   对右值引用。如果P是a   转发参考和参数是左值,类型为“左值”   引用A“代替A代表类型扣除。

标准还提供了以下示例:

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

这正是你的情况。

答案 2 :(得分:0)

由于模板&&中的含义不同,因此被称为通用引用

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

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

要使用raw函数,您必须执行以下操作:

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