【发布时间】:2016-11-17 14:20:00
【问题描述】:
如cplusplus.com 所述,std::forward 有两个签名:
template <class T> T&& forward (typename remove_reference<T>::type& arg) noexcept;
template <class T> T&& forward (typename remove_reference<T>::type&& arg) noexcept;
std::forward 的典型用途是在将参数传递给其他函数时保留右值性。让我们用一个例子来说明这一点:
void overloaded(int &) { std::cout << "lvalue"; }
void overloaded(int &&) { std::cout << "rvalue"; }
template <typename T>
void fwd(T && t)
{
overloaded(std::forward<T>(t));
}
当我们调用fwd(0) 时,T 推导出为int(t 的类型为int &&)。然后我们打电话给std::forward<int>(t)。该调用的结果是int && 类型的表达式,因此选择了overloaded 函数的第二个版本,程序将“rvalue”打印到标准输出。
当我们调用 fwd(i)(其中 i 是一些 int 变量)时,T 推导出为 int&(t 的类型为 int &)。然后我们打电话给std::forward<int&>(t)。该调用的结果(在应用引用折叠规则之后)是 int & 类型的表达式,因此选择了 overloaded 函数的第一个版本,程序将“左值”打印到标准输出。
在这两种情况下,我们都使用std::forward 的第一个重载(使用typename remove_reference<T>::type& arg 的那个)。这是因为即使t 的类型是int &&,它也会绑定到左值引用(因为“对某物的右值引用”类型的命名变量本身就是左值,而左值不能绑定到右值引用)。
问题 1:
std::forward 的第二次重载是为了什么?你能想出一些实际的例子,通过右值引用使用arg 的重载吗?
问题 2:
两个签名都返回相同的结果:
static_cast<decltype(arg)&&>(arg)
我的问题是,我很确定这是错误的。当我们尝试从std::forward 的第一个重载中返回它时,我们会得到一个编译错误。
当fwd 用int 右值调用时,它用T = int 调用std::forward 的第一个重载。然后,decltype(arg) 将变为int&,因此static_cast<decltype(arg)&&>(arg) 将折叠为static_cast<int&>(arg)。但是返回类型是int &&,我们得到编译错误:
cannot bind ‘std::remove_reference<int>::type {aka int}’ lvalue to ‘int&&’
std::forward 的两个重载版本都应返回 static_cast<T&&>(arg)。我说的对吗?
你认为来自 cplusplus.com 的引用是错误的吗?
【问题讨论】:
-
第一个问题的答案见stackoverflow.com/questions/38344332/…。
-
@TartanLlama 上面有一堆
const和const_cast。 -
cplusplus.com不是cppreference。cppreference.com是cppreference。了解其中的区别。 -
@Nawaz 指出差异可能与主题无关(我发现 cppreference 更可靠,我自己)
-
@Yakk 如果您发现错误,您可以随时自行修复:)
标签: c++ c++11 stl rvalue-reference rvalue