std::forward


std::forward 是 C++ 标准库中定义在 <utility> 头文件里的一个函数模板,它主要用于实现完美转发,也就是在函数模板中能够将接收到的参数(无论是左值还是右值,以及其对应的 constvolatile 等属性)原封不动地转发给其他函数,保证被转发函数接收到的参数特性和原调用函数传入的参数特性完全一致。下面我们来详细解析其源码实现。

源码形式

在 C++ 标准库中,std::forward 通常有两种重载形式,一种用于转发左值,另一种用于转发右值。以下是简化后的源码示意(不同编译器的具体实现可能会有细节差异,但核心逻辑是一致的):

// 用于转发左值的版本
template<typename T>
T& forward(typename std::remove_reference<T>::type& arg) noexcept 
{
    return static_cast<T&>(arg);
}

// 用于转发右值的版本
template<typename T>
T&& forward(typename std::remove_reference<T>::type&& arg) noexcept 
{
    return static_cast<T&&>(arg);
}

//VS019
_EXPORT_STD template <class _Ty>
_NODISCARD _MSVC_INTRINSIC constexpr _Ty&& forward(remove_reference_t<_Ty>& _Arg) noexcept 
{
    return static_cast<_Ty&&>(_Arg);
}

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

其实现非常简单,根据传入的参数类型,强转成对应的左值或者右值。

源码解析

模板参数 T
  • T 是一个模板类型参数,它的推导依赖于函数调用时传入的参数以及函数模板的上下文。在完美转发的场景中,T 通常是通过“万能引用”(T&&)来推导得到的。例如在一个函数模板中:
template<typename U>
void wrapper(U&& arg) 
{
    otherFunction(std::forward<U>(arg));
}

当调用 wrapper 函数时,如果传入的是左值,U 会被推导为左值引用类型;如果传入的是右值,U 会被推导为右值引用类型。

std::remove_reference<T>::type
  • std::remove_reference 是一个类型特征(type trait),它定义在 <type_traits> 头文件中。其作用是去除类型 T 的引用属性,返回一个非引用类型。在 std::forward 的实现中使用它,是为了避免引用类型的干扰,确保能够正确处理不同类型的参数。例如:
    • 如果 Tint&,那么 std::remove_reference<T>::type 就是 int
    • 如果 Tint&&,那么 std::remove_reference<T>::type 同样是 int
左值转发版本
template<typename T>
T& forward(typename std::remove_reference<T>::type& arg) noexcept 
{
    return static_cast<T&>(arg);
}
  • 参数部分typename std::remove_reference<T>::type& arg 表示接受一个左值引用参数 arg,其类型是去除 T 的引用属性后的类型。
  • 返回值部分static_cast<T&>(arg) 使用 static_cast 进行类型转换,将参数 arg 转换为 T& 类型并返回。当 T 被推导为左值引用类型时,这里就会正确地将参数以左值引用的形式转发出去。例如,如果在 wrapper 函数中传入左值,U 被推导为左值引用类型,那么调用 std::forward<U>(arg) 时,就会调用这个左值转发版本,保证参数以左值的形式被转发给 otherFunction
右值转发版本
template<typename T>
T&& forward(typename std::remove_reference<T>::type&& arg) noexcept
{
    return static_cast<T&&>(arg);
}
  • 参数部分typename std::remove_reference<T>::type&& arg 表示接受一个右值引用参数 arg,同样其类型是去除 T 的引用属性后的类型。
  • 返回值部分static_cast<T&&>(arg) 使用 static_cast 进行类型转换,将参数 arg 转换为 T&& 类型并返回。当 T 被推导为非引用类型时,根据引用折叠规则(T&& 在这里仍然是右值引用),就会正确地将参数以右值引用的形式转发出去。
引用折叠

& + && = & 左值引用 + 右值引用 = 左值引用
&& + && = && 右值引用 + 右值引用 = 右值引用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值