红魔咖啡馆

头发越掉越多,头发越掉越少

0%

【C++】完美转发

完美转发

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
using namespace std;
void f(const string& s){
  cout <<"左值:"<<s<<endl;
}
void f(string&& s){
  cout <<"右值"<<s<<endl;
}

void g(const string& s){
  f(s);
}
void g(string&& s){
  f(s);
}

int main(){
  // 右值
  g(string("hello1"));

  // 左值
  string s1("hello2");
  g(s1);
}

这段代码,我们希望让右值调用右值的重载函数f,左值调用左值的重载函数f,但最后结果均调用了左值重载函数

这是因为在函数g中,s本身是一个局部变量,拥有地址,是一个左值

这时候我们需要进行类型转换

std::forward

我们当然可以使用static_cast<>()来进行转换,但是这里可以使用forward<>()函数进行转换,结合函数模板,使得代码更加方便易读

1
2
3
4
template<class T>
void g(T&& s){
  f(forward<T>(s));
}

这里在形参列表中T&& s被称为万能引用或转发引用

它既可以绑定左值也可以绑定右值,会在实例化时根据传入参数类型自动推导成对应类型

T的类型取决于传入的是左值还是右值

  • 左值:T被推导为实参类型的引用
  • 右值:T被推导为实参类型的非引用

forward函数实现了一个类型转换

  • 若传入实参是右值,则forward函数会返回一个右值引用
  • 若传入实参是左值,则函数模板T会被替换为该类型的引用,但此时会出现引用的引用(&&&),这时遵循引用折叠规则,得到类型的左值引用

即除了右值引用的右值引用被折叠为右值引用外,其余的只要有左值引用,就会被折叠为左值引用