我正在尝试理解rvalue
引用。我已经看到它们如何在构造函数中使用std::move
和std::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);
}
为什么它适用于功能模板版本?
答案 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)
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