在上一篇博客中我们知道了什么是移动语意以及完美转发,在这期间我们使用了两个新的std函数: std::move 与 std::forward。
- std::move 的作用:将一个左值转换为一个右值
- std::forward的作用:将实参的左右值属性在实参转发时完整保留。
我们理解了移动语意以及完美转发后,有必要探究一下std::move 与 std::forward两个函数的内部实现,这需要一些关于C++模板的基本知识:
1. 模板的类型推断、右值引用的特殊类型推断规则
2.实参转发
3.通用引用
先说通用引用,这是Scott Meyers自创的一个词,通俗地讲,通用引用是这样一个东西:它既能绑定左值又能绑定右值,在代码中一般长这个样子:T&&。通用引用有两个条件:
- 必须精确地满足“T&&”这种形式,不能加const等修饰。
- T必须是通过推断得到的,最常见的例如模板参数。
4.引用折叠
C++模板的类型推导(Type Decuction)过程中的“引用折叠”规则:
- T& & => T&
- T&& & => T&
- T& && => T&
- T&& && => T&&
5. static_cast
6. 无名右值引用、具名右值引用
std模板库中forward与remove_reference的实现
//std::remove_reference的实现
template <typename T>
struct remove_reference{ typedef T type}
template <typename T>
struct remove_reference<T&>{ typedef T type}
template <typename T>
struct remove_reference<T&&>{ typedef T type}
//std::move的实现
template<typename T>
typename std::remove_reference<T>::type&& move(T&& arg){
return static_cast<typename std::remove_reference<T>::type&&>(arg);
}
//std::forward的实现
template <typename T>
T&& forward(typename remove_reference<T>::type& arg){
return static_cast<T&&>(arg);
}
在了解了C++模板的一些奇技淫巧之后,我们不难看出来,move函数啥都没干,只是将一个左值或者左值引用在编译期转换成一个右值引用。forward函数利用引用折叠规则,将实参是左值引用还是右值引用这个信息保留下来作为返回值。
简单来讲std::move 跟 std::forward只是在编译期做了个类型转换的工作:move返回一个右值引用,forward返回左值引用或者右值引用(参数是左值(引用)就返回左值引用,是右值(引用)就返回右值引用)——没有任何运行期的代码。