【发布时间】:2021-08-04 13:07:44
【问题描述】:
我知道std::forward的第二次重载:
template< class T >
constexpr T&& forward( std::remove_reference_t<T>&& t ) noexcept;
用于右值(如 Howard Hinnant 在他的回答中所述:How does std::forward receive the correct argument?)
在cppreference.com 使用此重载时有一个示例(Praetorian 在How does std::forward receive the correct argument? 中也提到过):
- 将右值作为右值转发并禁止将右值作为左值转发 此重载可以将表达式(例如函数调用)的结果(可能是右值或左值)转发为转发引用参数的原始值类别.
例如,如果一个包装器不只是转发它的参数,而是在参数上调用一个成员函数,并转发它的结果:
// 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())>?
Cppreference 状态:
此重载可以将表达式(例如函数调用)的结果(可能是右值或左值)转发为转发引用参数的原始值类别。
举个例子:
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()));
不过,我无法理解为什么有人需要添加外前锋。
编辑:编辑移至后续问题:RValue-reference overload of std::forward potentially causing dangling reference?
【问题讨论】:
-
您引用了一些未知来源。在包含“示例,如果包装器没有”的引号上方搜索该字符串的链接不显示该字符串?上面的“引用”部分应该是引用,还是只是格式错误?
-
你在假装引用的同时进行释义吗?我很困惑吗?你放错链接了吗?
-
这可能只是复杂模板编程场景中可能发生的一个示例。进一步简化:我们可能希望像
myForward<int>(42);这样的代码能够编译,如果没有std::remove_reference_t<T>&& t重载,它将无法编译。
标签: c++ c++11 perfect-forwarding