前言
在之前的很多文章中,都提到了移动构造,移动赋值这些,简单理解就是对资源的转移。
牵扯到C11的基本问题:右值是什么(在C11中右值的定义更加明确)。
函数重载:参数为引用接收时
下面三个函数可以重载,在之前的学习中,得知函数重载需要函数名相同,参数列表不同;
在C11中,参数的类型不同也可重载,比如下面就是左值引用和右值引用的区别。
void fun(int& a)
{
cout << "fun(int& a)" << endl;
}
void fun(const int& a)
{
cout << "fun(const int& a)" << endl;
}
void fun(int&& a)
{
cout << "fun(int&& a)" << endl;
}
int main(void)
{
int x = 10;
const int y = 20;
fun(x);
fun(y);
fun(30);
return 0;
}
在运行后,可以看出编译器知道该把什么样的参数传给哪个函数:
但在与模板函数关联起来时,就会出现问题:
模板函数里调用重载的函数出现的问题
void fun(int& a)
{
cout << "fun(int& a)" << endl;
}
void fun(const int& a)
{
cout << "fun(const int& a)" << endl;
}
void fun(int&& a)
{
cout << "fun(int&& a)" << endl;
}
template<typename T>
void fac(T&& a)
{
fun(a);
}
int main(void)
{
int x = 10;
const int y = 20;
fac(x);
fac(y);
fac(30);
return 0;
}
运行结果:
这个函数将右值(30)当成了左值,调用了重载函数的第一个。
原因:
在右值具有名字后,在该示例中,30传递给模板函数的形参a,使其具有了别名,这时候就成了左值,所以调用的第一个已重载的函数。
解决方法:
完美转发(Perfect Forwarding):是指在函数模板中,完全依照模板的参数的类型(即保持参数的左值、右值特征),将参数传递给函数模板中调用的另外一个函数。C++11中提供了这样的一个函数std::forward,它是为转发而生的,不管参数是T&&这种未定的引用还是明确的左值引用或者右值引用,它会按照参数本来的类型转发。
示例:
void fun(int& a) //lvalue
{
cout << "fun(int& a)" << endl;
}
void fun(const int& a) // const lvalue
{
cout << "fun(const int& a)" << endl;
}
void fun(int&& a) // rvalue
{
cout << "fun(int&& a)" << endl;
}
template<typename T>
void fac(T&& a)
{
fun(std::forward<T>(a)); // 完美转发
}
int main(void)
{
int x = 10;
const int y = 20;
fac(x);
fac(y);
fac(30);
return 0;
}