c++11学习笔记(5)- 引用折叠和完美转发

C++通过引入一条所谓“引用折叠”的语言规则,并结合模板推导来完成完美转发的。
首先看一个例子:

template<typename T>
void testFunc(T& r)
{
	
}

当我们给函数传入引用时,如果我们对函数 testFunc 传入一个非引用类型的数据,那么形参中r的类型时什么呢?传入一个右值引用,形参r中的类型是什么呢?如果函数参数声明的类型是右值引用,传入左值引用结果又会怎样呢?

模板对类型的推到规则和简单,当转发函数的实参是类型T的左值引用,那么模板参数被推导为T&类型;如果转发函数的实参是类型T的右值引用,那么模板参数被推导为T&&类型。
具体引用折叠可以参照下表:

函数参数声明的类型 传入实参的类型 r的类型
T& TR r&
T& TR& r&
T& TR&& r&
T&& TR r&&
T&& TR& r&
T&& TR&& r&&

从上表可以看出无论传入什么类型,右值引用都可以保持跟出入的实参类型保持不变。
所以,我们可以这么写完美转发的模板:

template<typename T>
void perfectForward(T&& t)
{
	func(std::forward<T>(t));
}
  • 当传入的为一个const T类型实参时,如果不适用右值引用,则需要声明一个const T的函数版本,因为const T&无法转换为T&,由于使用的右值引用我们就可以完全不用声明带有const版本的转发函数。
  • 使用std::forward是为了保证函数可以调用正确形参形式的函数。

下面是一个不带std::forward的示例:

#include 
#include 
#include 

void func(int& t)
{
	std::cout << "func(int& t)" << std::endl;
}

void func(const int& t)
{
	std::cout << "func(const int& t)" << std::endl;
}

void func(const int&& t)
{
	std::cout << "func(const int&& t)" << std::endl;
}

template<typename T>
void perfectForward(T&& t)
{
	//func(std::forward(t));
	func(t);
}

int main(int argc, char** argv)
{
	int a = 0;
	perfectForward(a);

	const int b = 20;
	perfectForward(b);

	perfectForward(std::move(a));

	system("pause");
	return 0;
}

函数的运行结果为:
func(int& t)
func(const int& t)
func(int& t)

但是我们想让调用函数 perfectForward(10); 的时候调用函数 void func(const int&& t) 因为std::move(a)是一个右值引用。而由于引用折叠的作用,当传入一个右值到形参 T& 中会被认为推导为左值。因此,需要是使用std::forwardstd::forward的作用就是强制转化为实际类型的值作为形参。
更改为std::forward 后,运行效果为:
func(int& t)
func(const int& t)
func(const int&& t)


作者:douzhq
个人主页:https://www.douzhq.cn
文章同步页:https://douzhq.cn/c11_5/

你可能感兴趣的:(C++,c++11,std::forward,完美转发)