c++万能引用、完美转发

一、万能引用

只有两种形式的引用:左值引用和右值引用,万能引用不是一种引用类型,而是代表要么是左值引用要么是右值引用。

1、万能引用用在需要推断类型的场合,即以下两种场合:

a)用在模板

template
void  tempFun(T&& t) {}  //模板类型的这种用法 T && 是万能引用最常见的使用场合

b)auto推断类型

auto&& var2 = var1;  //auto这种需要推断类型的地方

万能引用虽然跟右值引用的形式一样,但右值引用需要是确定的类型,如: int && ref = x;

2、万能引用能够接收左值或右值,返回左值引用或右值引用

template
void  tempFun(T&& t)
{
	t = 40;
	cout << t << endl;
}

int main()
{
	int x = 19;
	tempFun(x); //T为int, t为int & ,即左值引用, 函数模板中对t的改动为影像x的值
	tempFun(30);//T为int, t为int&&,即右值引用

	int &&r = 100;
	tempFun(r);   //虽然r绑定到一个右值,但r变量本身是个左值(因为他出现在=的左边)
	return 0;
}

尤其要注意:int &&r = 100; 这种形式r虽然绑定右值,但r本身是个左值。3、auto类型推断

3、auto会推断类型,所以也可以用万能引用

auto推断类型是在编译器就确定了,不是在运行期。4、

	int v1 = 100;
	auto && r1 = v1;  //auto为int,r1的类型为int &
	auto&& r2 = 200;  //auto为int,r2的类型为int &&

4、注意区分万能引用和右值引用,只有形如 T && 的形式才是万能引用

如下void fun(T && t); 中T&&并不是万能引用,因为T的类型在模板实例化时已经确定,当实例函数void fun(T && t);时 T的类型已经确定。

template
class A
{
	void fun(T && t); //这里是右值引用
};

 但如下是万能引用:

template
class A
{
	template
	void fun(U && u); //这里是万能引用
};

5、与c++11之前的标准比较....

老版本c++,是没有右值引用这个概念的,故也没有万能引用的概念,如果我要实现技能接收左值又能接收右值,需要用const重载....

template
void tempTest(T & t) {}   //接收左值

template
void tempTest(const T & t) {}  //虽然能同时匹配左值和右值,但会给左值强制const

二、完美转发

使用场景:通过函数模板调用另外一个函数,如:

template
void  tempFun(F f, T && t1, U && t2)
{
	f(t1, t2);
}

我们已经知道模板中使用万能引用是有益的,这样既能接收左值也能接收右值。但对于函数内部来说不管接收的是左值还是右值,模板函数内部对于形参都是左值(T && t1=var, t1本身是左值)。

此时如果f函数的第一个参数需要右值,我们必须这样调用:f(std::move(t1), t2);

但模板是通用的,我们不能直接用std::move()写死,这样就不能调用接收左值的函数了。

c++标准提供std::forward<>模板类来保持参数的原有类型,代码如下:

template
void  tempFun(F f, T && t1, U && t2)
{
	f(std::forward(t1), std::forword(t2));
}

这样传过来的参数t1、t2的类型被直接转发到函数f()中去,称为完美转发。

这样传递左值还是右值就有调用tempFun()函数参数的调用者来确定了。

完美应该把以上模板作为范例,即模板类型参数都用T&&格式的万能引用,需要调用函数的时候,参数都用std::forward<>()来进行传递。

你可能感兴趣的:(c++,c++)