【发布时间】:2019-08-03 11:24:41
【问题描述】:
(constexpr 和 noexcept 被忽略了,因为它们似乎与了解 std::forward 的行为方式无关。)
基于我对 Scott Meyers 的“Effective Modern C++”的理解,
C++14 中std::move 的示例实现如下
template<typename T>
decltype(auto) move(T&& param) {
return static_cast<remove_reference_t<T>&&>(param);
}
鉴于对转发(或“通用”)引用的解释,我认为这个实现对我来说非常清楚:
- 参数
param是T&&类型,即右值引用或左值引用(无论参数的类型是什么),取决于调用者中参数是右值还是左值;换句话说,param可以绑定到右值和左值(即 anything);这是有意的,因为move应该将 anything 转换为右值。 -
decltype(auto)只是根据实际的return语句表达返回类型的简洁方式。 - 返回的对象是同一个对象
param,被转换为一个右值引用(&&),无论T是什么类型,一旦其推导的引用被剥离(推导在T&&上完成,不在⋯<T>&&)。
简而言之,我对在move的实现中使用转发/通用引用的理解如下:
- 转发/通用引用
T&&用于参数,因为它旨在绑定到任何东西; - 返回类型是一个右值引用,因为
move旨在将任何东西转换为右值。
很高兴知道我的理解到目前为止是否正确。
另一方面,std::forward 在 C++14 中的示例实现如下
template<typename T>
T&& forward(remove_reference_t<T>& param) {
return static_cast<T&&>(param);
}
我的理解如下:
-
T&&,返回类型,必须是转发/通用引用,因为我们希望是对传递给forward通过右值引用或左值引用返回,因此在此处的返回类型上进行类型推导(与发生的情况不同对于move,类型推导发生在参数端)forward的模板类型参数的右值引用; - 因为
T编码了实际参数的左值/右值特性,该参数绑定了作为参数传递给forward的调用者参数,T本身可能导致actual_type&或actual_type,因此T&&可以是左值引用或右值引用。 -
param的类型是对T的任何类型的左值引用,一旦其推导引用被剥离。 Actually instd::forwardtype deduction is disabled on purpose, requiring that the template type argument be passed explicitly.
我的疑惑如下。
-
forward的两个实例(实际上,每个调用它的类型都有两个)仅在返回类型上有所不同(传递右值时的右值引用,传递左值时的左值引用),因为在两者中案例param是对非const无引用T的左值引用。返回类型不是不计入重载决议的东西吗? (也许我在这里不正确地使用了“过载”。) - 既然
param的类型是非const的左值引用到无引用T,并且因为左值引用必须是to-const才能绑定到右值,@987654365怎么能@绑定到右值?
作为一个附带问题:
- 可以将
decltype(auto)用作返回类型,就像move一样?
【问题讨论】:
-
std::forward的第二个重载是forward(remove_reference_t<T>&& param),而remove_reference不会删除 cv-qualifiers -
@PiotrSkotnicki,现在我看到std::forward 实际上有两个重载。我想知道为什么迈耶斯的书中只提到了前者……
-
你忘了
constexpr和noexcept。 -
@Deduplicator,这两个家伙是了解
std::forward工作原理的必要条件吗? -
@EnricoMariaDeAngelis 仅当您也想了解它们影响的部分时。或者至少不想给人留下错误的印象,也不想解释把他们排除在外。
标签: c++ move rvalue-reference perfect-forwarding forwarding-reference