完美转发
在函数模板中,可以将参数“完美”的转发给其它函数。所谓完美,即不仅能准确的转发参数的值,还能保证被转发参数的左、右值属性不变。
C++11标准引入了右值引用和移动语义,所以,能否实现完美转发,决定了该参数在传递过程使用的是拷贝语义还是移动语义。
为了支持完美转发,C++11提供了以下方案:
1)如果模板中(包括类模板和函数模板)函数的参数书写成为T&& 参数名,那么,函数既可以接受左值引用,又可以接受右值引用。
2)提供了模板函数std::forward(参数) ,用于转发参数,如果 参数是一个右值,转发之后仍是右值引用;如果参数是一个左值,转发之后仍是左值引用。
注意
参数书写成为T&& 参数名
但并不是说它是右值引用,类似int&&这才是右值引用
#include <iostream>
using namespace std;
//完美转发
void func1(int &i)
{
cout << "参数是左值=" << i << endl;
}
void func1(int &&i)
{
cout << "参数是右值=" << i << endl;
}
void func2(int i)
{
func1(i);
}
void func3(int &&i)
{
func1(i);
}
void func3(int &i)
{
func1(i);
}
void func4(int &&i)
{
func1(move(i));
}
void func4(int &i)
{
func1(i);
}
template <typename T>
void func5(T &&i)
{
func1(move(i));
}
template <typename T>
void func5(T &i)
{
func1(i);
}
template <typename T>
void func6(T &&i)
{
func1(forward<T>(i));
}
void func7(int &&i)
{
func1(forward<int>(i));
}
void test()
{
int i = 3;
func1(i);
func1(33);
/* 参数是左值=3
参数是右值=33 */
//上面代码调用,不会出现问题,但是如果不是字节调用,中间由其它函数中专,那中专的函数该怎么写呢?
func2(i);
func2(33);
/* 参数是左值=3
参数是左值=33 */
//上面代码输出结果可以看出,不是我们想要的,我们想要的是:func2()把参数传给func1()的时候,也要有左值和右值之分
//如果参数在传递的过程中不能保持左/右值的属性,那就不能实现移动语义了.
func3(i);
func3(33);
/*参数是左值=3
参数是左值=33 */
//上面代码也不是我们想要的
func4(i);
func4(33);
/*参数是左值=3
参数是右值=33 */
//上面代码是我们想要的,但是该方法不是最好的,类似的还有下面的,改成两个模板
func5(i);
func5(33);
/*参数是左值=3
参数是右值=33 */
cout << "------------------" << endl;
//使用最佳,C++11提供完美语义
func6(i);
func6(33);
}
int main()
{
test();
return 0;
}
参数是左值=3
参数是右值=33
参数是左值=3
参数是左值=33
参数是左值=3
参数是左值=33
参数是左值=3
参数是右值=33
参数是左值=3
参数是右值=33
------------------
参数是左值=3
参数是右值=33