我知道
std::forward
的第二次超载:
template< class T >
constexpr T&& forward( std::remove_reference_t<T>&& t ) noexcept;
用于右值(如 Howard Hinnant 在他的回答中所述:std::forward 如何接收正确的参数?)
在 cppreference.com 有一个何时使用此重载的示例(Praetorian 的std::forward 如何接收正确的参数? 中也提到过):
- 将右值作为右值转发,并禁止将右值作为左值转发。此重载使得可以将表达式(例如函数调用)的结果(可能是右值或左值)转发为转发引用参数的原始值类别。
例如,如果包装器不仅转发其参数,而是调用该参数的成员函数,并转发其结果:
// transforming wrapper template<class T> void wrapper(T&& arg) { foo(forward<decltype(forward<T>(arg).get())>(forward<T>(arg).get())); }
arg 的类型可能是
struct Arg { int i = 1; int get() && { return i; } // call to this overload is rvalue int& get() & { return i; } // call to this overload is lvalue };
我真的不明白这个例子。为什么还需要外前锋
forward<decltype(forward<T>(arg).get())>
?
Cpp参考状态:
此重载使得可以转发表达式(例如函数调用)的结果,该结果可以是右值或左值,作为转发引用参数的原始值类别。
举个例子:
void func(int& lvalue)
{
std::cout << "I got an lvalue!" << std::endl;
}
void func(int&& rvalue)
{
std::cout << "I got an rvalue!" << std::endl;
}
template <typename T>
T&& myForward(typename std::remove_reference_t<T>& t)
{
return static_cast<T&&>(t);
}
struct foo
{
int i = 42;
int& get()& { return i; }
int get()&& { return i; }
};
template <typename T>
void wrapper(T&& t)
{
func(myForward<T>(t).get());
}
int main()
{
foo f;
wrapper(f);
wrapper(foo());
return 0;
}
打印:
I got an lvalue!
I got an rvalue!
很好,没有外部转发,同时它还转发“表达式的结果[...]作为转发引用参数的原始值类别”。它甚至不需要
std::forward
的第二次过载。仅当像这样调用 func()
时才需要此重载:
func(myForward<decltype(myForward<T>(t).get())>(myForward<T>(t).get()));
尽管如此,我还是无法理解为什么有人需要添加外部转发。
编辑:编辑移至后续问题:std::forward 的 RValue 引用重载可能导致悬空引用?