std::move 和 std::forward源码解析

std::move和std::forward仅仅是执行转换(cast)的函数(事实上是函数模板)。std::move无条件的将它的实参转换为右值,而std::forward只在特定情况满足时下进行转换。

std::move

template <class _Ty>
constexpr remove_reference_t<_Ty>&& move(_Ty&& _Arg) noexcept {
    return static_cast<remove_reference_t<_Ty>&&>(_Arg);
}

std::move函数模板返回一个remove_reference_t<_Ty>&&,确保返回的一定是右值。

std::forward

template <class _Ty>
constexpr _Ty&& forward(remove_reference_t<_Ty>& _Arg) noexcept {
    return static_cast<_Ty&&>(_Arg);
}

template <class _Ty>
constexpr _Ty&& forward(remove_reference_t<_Ty>&& _Arg) noexcept {
    static_assert(!is_lvalue_reference_v<_Ty>, "bad forward call");
    return static_cast<_Ty&&>(_Arg);
}

std::forward函数模板使用时显示指明模板参数类型,根据条件进行类型转换。

std::forward完美转发

void process(Widget& lval) {
    std::cout << "左值process" << std::endl;
}
void process(Widget&& lval) {
    std::cout << "右值process" << std::endl;
}
template<typename T>
void logAndProcess(T&& param) {
    process(temp::forward<T>(param));
}
Widget w;
logAndProcess(w);
logAndProcess(Widget());

logAndProcess模板函数,使用通用引用的形式进行模板类型推导,如果传入左值,TParam都会被推导为左值引用;如果传入右值,就正常推导,即T推导为Widget,param推导为Widget&&。

所以logAndProcess(w)函数体中,T为Widget&,param为Widget&,forward<T>(param)会调用forward(remove_reference_t<_Ty>& _Arg)版本的重载函数,返回static_cast<_Ty&&>(_Arg),根据引用折叠的规则,注意这里的_Ty为Widget&,Widget& && 就是Widget&,返回左值引用。

logAndProcess(Widget())函数体中,T为Widget,param为Widget&&,forward<T>(param)会调用forward(remove_reference_t<_Ty>&& _Arg)版本的重载函数,返回static_cast<_Ty&&>(_Arg),_Ty为Widget,所以返回Widget&&,即右值引用。

std::forward<Widget>(w) 和 std:forward<Widget&>(w)

std::forward<Widget>(w)返回右值,std:forward<Widget&>(w)返回左值,他们两个都会调用forward(remove_reference_t<_Ty>& Arg)版本的重载函数,因为_Ty类型的不同和引用折叠,一个返回右值,一个返回左值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值