万能引用、完美转发

万能引用

万能引用的格式如下:

template<typename T>
void PerfectForward(T&& t)
{
	Fun(t);
}

虽然写的是&&和右值引用类似,但是它可以接收左值引用和右值引用

当传过来的是左值,那么T&&会折叠为T&

引用折叠有以下几种情况:

实参 形参 结果
&(左值) &(左值) &(左值)
&(左值) &&(右值) &(左值)
&&(右值) &&(右值) &&(右值)
&&(右值) &(左值) &(左值)

举个栗子😉

void Fun(int& x) { cout << "左值引用" << endl; }
void Fun(const int& x) { cout << "const 左值引用" << endl; }

void Fun(int&& x) { cout << "右值引用" << endl; }
void Fun(const int&& x) { cout << "const 右值引用" << endl; }



template<typename T>
void PerfectForward(T&& t)
{
	Fun(t);
}

int main()
{
	PerfectForward(10);           // 右值

	int a;
	PerfectForward(a);            // 左值
	PerfectForward(std::move(a)); // 右值

	const int b = 8;
	PerfectForward(b);		      // const 左值
	PerfectForward(std::move(b)); // const 右值

	cout << "----------------------------------" << endl;

	return 0;
}

这里输出为什么都是左值引用呢?

chatgpt的回答:

这是因为在 C++ 中,当一个命名的变量被作为参数传递给函数时,它会被视为左值,即使该变量是通过 std::move 显式转换为右值引用的。

我的理解:

因为无论是什么类型作为函数参数接收,就有了载体,就会存在一片空间去存储值了,因此原来的右值有了空间只会就有了地址,就会被认为是左值。

这种情况也被称为不完美转发。

完美转发

经过引用折叠之后,传之前的数据的引用类型和传入之后的引用类型可能发生变化,为了保证类型不会发生变化,完美转发就产生了。

std::forward<>();

对于之前的代码,加上万能转发就能够正确输出类型了。

void Fun(int& x) { cout << "左值引用" << endl; }
void Fun(const int& x) { cout << "const 左值引用" << endl; }

void Fun(int&& x) { cout << "右值引用" << endl; }
void Fun(const int&& x) { cout << "const 右值引用" << endl; }



template<typename T>
void PerfectForward(T&& t)
{
	Fun(std::forward<T>(t));
}

int main()
{
	PerfectForward(10);           // 右值

	int a;
	PerfectForward(a);            // 左值
	PerfectForward(std::move(a)); // 右值

	const int b = 8;
	PerfectForward(b);		      // const 左值
	PerfectForward(std::move(b)); // const 右值

	cout << "----------------------------------" << endl;

	return 0;
}

注意:只要使用了完美转发,每一步调用涉及到参数的都必须加上万能转发,不然就会失败。

posted @ 2023-08-24 22:30  Hayaizo  阅读(15)  评论(0编辑  收藏  举报