【发布时间】:2020-12-28 06:05:11
【问题描述】:
转发引用定义如下: “转发引用是一种特殊的引用,它保留函数参数的值类别,从而可以通过 std::forward 转发它。” (https://en.cppreference.com/w/cpp/language/reference)
通过“保留函数参数的值类别”,我理解类型为转发引用的参数变量的名称与函数调用中的值类别相同。 例如:
template<typename T>
void wrapper(T&& forwarded_argument) {
some_function(forwarded_argument);
}
wrapper(5);
wrapper(my_int);
这里,第一次调用中的表达式5是prvalue,所以据我理解,some_function(forwarded_argument);中的表达式forwarded_argument(只是变量的名称)也应该是prvalue。
在第二次调用中,名称my_int 是一个左值,所以我希望some_function(forwarded_argument); 中的表达式forwarded_argument 是一个左值。
这将使这行写成std::forward<T>(forwarded_argument) 不必要,因为在这两种情况下,根据我传递给wrapper 的内容,无论如何都会调用some_function 的正确重载。
我也认为我不完全理解 std::forward 的实际作用。这是我找到的一个简化实现 (The implementation of std::forward):
template <class T>
inline T&& forward(typename std::remove_reference<T>::type& t) noexcept {
return static_cast<T&&>(t);
}
template <class T>
inline T&& forward(typename std::remove_reference<T>::type&& t) noexcept {
static_assert(!std::is_lvalue_reference<T>::value, "Can not forward an rvalue as an lvalue.");
return static_cast<T&&>(t);
}
正如 cppreference 所述 (https://en.cppreference.com/w/cpp/language/value_category),对对象类型(例如 static_cast<char&&>(x))的右值引用的强制转换表达式是一个 xvalue。我没有看到任何提及x 的值类别,所以我假设整个转换表达式的值类别无论如何都是相同的。函数调用表达式的值类别,其返回类型是对对象的右值引用,是一个 xvalue。由此看来,无论我将什么传递给std::forward,对std::forward 的调用的值类别最终都会是一个xvalue。
这里的错误在哪里?从通常的转发方式来看,问题的两个部分(关于转发引用和关于std::forward)的结论似乎都不正确。
【问题讨论】:
-
_forwarded_argument始终是左值。见:Rvalues, lvalues and formal definitions -
那么定义中的“保留函数参数的值类别”部分到底是什么意思,如果不是这样呢?
-
意思是:
std::forward<T>(arg)与参数具有相同的值类别。但是arg本身没有。 -
对
wrapper的调用中的<int>不应该存在,这是我的疏忽,我将其编辑了。