一、什么是完美转发
提到完美转发,就有必要说一下,什么是转发,什么样的转发才称得上是完美转发。
在C++中,转发指的就是函数之间的参数传递(例如函数f1
接收了一个参数a
,而后又将此参数a
传递给了其函数体内调用的另一个函数f2
)
而完美转发指的就是在函数之间传递参数的过程中,参数在传递后的属性保持不变(如左值仍是左值,右值仍是右值,const
修饰也会保留)。
二、常规转发存在的问题
对于普通的转发,参数在函数间传递时属性可能会发生改变,我们看一个例子。
#include <iostream>
#include <utility>
void an_orther_fun(int a, int& b)
{
std::cout << "in an_orther_fun(): a = " << a << ", b = " << ++b << std::endl;
}
void transmit(int a, int b)
{
an_orther_fun(a, b);
}
int main()
{
int a = 2, b = 3;
std::cout << " before transmit(): a = " << a << ", b = " << b << std::endl;
transmit(a, b);
std::cout << " after transmit(): a = " << a << ", b = " << b << std::endl;
return 0;
}
其输出为:
before transmit(): a = 2, b = 3
in an_orther_fun(): a = 2, b = 4
after transmit(): a = 2, b = 3
注意,函数an_orther_fun()
的第二个参数类型是引用int&
,并且我们在函数中给该引用的值加上了1(++b
那里),也就是我们预期应当会修改其第二个参数的值加1
。但根据输出,虽然我们在an_orther_fun()
打印出了加1
后的b
的值。但在外层,我们执行tansmit()
后,b
的值并没有加 1。
这里的原因其实很显而易见的,就是我们b
在从transmit()
传递到an_other_fun()
的时候,其属性已经改变了:transmit()
中的b
是外层b
的一个副本,而不是引用。
这就是常规引用可能带来的转发问题。
你可能会说,我们将transmit()
的第二个参数类型也改为引用int&
不就可以解决了吗?
void transmit(int a, int& b) {
... }
在我们这个示例中,这样的修改确实是可以达成我们示例中的目的的。
但,这只是示例,实际还有更多的可能性。例如,如果上例中的b
处是一个右值引用,怎么办?我们看下面的代码:
#include <iostream>