Effective Modern C++ 之 std::forward

std::forward与std::move的行为机制很类似。前面我们讲过std::move的实质是对传入的实参进行强制类型转换,最终转换为右值。从这里我们可以看出std::move实施的强制类型转换是无条件的。std::forward最长使用的场景是:函数模板以万能引用为新参,任何调用另一个函数。现在先让我们看一个简单的测试案例:

void fun1(std::string& str) {
	std::cout << "fun1 "<< "左值" << std::endl;
}
void fun1(std::string&& str) {
	std::cout << "fun1 " << "右值" << std::endl;
}
template<typename T>
void _fun(T&& t) {
	fun1(std::forward<T>(t));
}

int main(void)
{
	std::string str = "Jay";
	fun1(str);
	fun1("Jay");

	return 0;
}

从案例中我们便可以知道:当且仅当传入_fun()的实参是个右值,则调用fun1()时传入的也是右值。当且仅当传入_fun()的实参是个左值,则调用fun1()时传入的也是左值(从这里也可以看出std::forward也被称为完美转发)。为什么会这样呢?std::forward的底层实现与std::move的底层实现几乎是一模一样的。唯一不同的是:std::forward是有条件进行强制类型转换,当给_fun()传入的实参是个右值的情况下,它才会向右值执行强制类型转换。(当传入的是左值时,不需要进行强转,传递给调用的函数的实参就是左值。当传入的是右值时,在万能引用的条件下,可能会发生引用折叠,所以必须强转)。

std::forward()可以实现完美转发,完美转发的含义时我们不仅可以转发对象,还可以转发对象的显著型别:型别,是左值还是右值,以及是否带有const或volation饰词等。但是在有些情况下会存在完美转发失败的情况:

  • 大括号初始化的应用。
  • 把0和Null以空指针之名传递给模板,型别推导就会发生行为扭曲(推导结果是整型,而不是指针型别)。
  • 仅有声明的整型static const的成员变量。
  • 重载的函数名字和模板。
发布了78 篇原创文章 · 获赞 11 · 访问量 5073

猜你喜欢

转载自blog.csdn.net/qq_43145594/article/details/104248708