对于所有重载,返回类型已指定为 T&&
(忽略 constexpr
)。
但是在下面这个例子所附的描述中:
template<class T>
void wrapper(T&& arg)
{
// arg is always lvalue
foo(std::forward<T>(arg)); // Forward as lvalue or as rvalue, depending on T
}
如果对 wrapper() 的调用传递右值 std::string,则 T 是 推导为 std::string(不是 std::string&、const std::string& 或 std::string&&) 和 std::forward 确保右值引用是 传递给 foo。
如果对 wrapper() 的调用传递了一个 const 左值 std::string,然后将 T 推导为 const std::string&,并且 std::forward 确保将 const 左值引用传递给 foo。
如果对 wrapper() 的调用传递了一个非常量左值 std::string,则 T 推导为 std::string&,而 std::forward 确保非 const 左值引用传递给 foo。
在第一个之后的两个实例中,左值引用而不是右值引用(正如 T&&
所暗示的那样,这种理解是否正确?)已被记录为传递给 foo。
如果上面的理解是正确的,为什么返回值被指定为T&&
?
最佳答案
有区别
void f1(int&& a) {}
template<class T>
void f2(T&& a) {}
第一个版本是定义 f1
来处理右值。另一方面,第二个版本是一个模板函数,接受通用(或在某些引用中,转发)引用作为其参数。
要了解 std::forward
的机制,您应该使用不同的参数调用 f2
,如:
#include <iostream>
template <class T> void f2(T &&a) { std::cout << __PRETTY_FUNCTION__ << '\n'; }
int main() {
int a{5};
f2(5);
f2(a);
return 0;
}
当您编译代码时,比如使用 g++
,您会从程序中获得以下输出:
./a.out
void f2(T &&) [T = int]
void f2(T &&) [T = int &]
如您所见,在第一次调用中 T
被推断为 int
,而在第二次调用中它被推断为 int &
。由于引用折叠规则,正如您的问题的评论中已经提到的, T &&
会给你 T
而 T& &&
会给你T&
。简而言之,您观察 T&&
作为返回类型并不意味着函数返回右值引用。实际上,在模板函数中,&&
就像一个恒等运算符。当与 T&
组合时,它会给你 T&
;否则,它会给你 T
。
有一个really nice talk在 CppCon2016 上,Arthur O'Dwyer 就此主题进行了讨论。也许您可以看一下它以了解模板类型推导规则,这将帮助您阐明 std::forward
行为。
关于c++ - 寻求对 std::forward 的澄清,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49215492/