对于所有重载,返回类型已指定为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()的调用传递了一个rvalue std :: string,那么T就是 推导为std :: string(不是std :: string&amp;,const std :: string&amp;,或 std :: string&amp;&amp;)和std :: forward确保rvalue引用 传给了foo。
如果对wrapper()的调用传递了一个const值 std :: string,然后将T推导为const std :: string&amp;,和 std :: forward确保将const左值引用传递给foo。
如果对wrapper()的调用传递非const左值std :: string,则为T. 推导出std :: string&amp;和std :: forward确保非const 左值引用传递给foo。
在第一个之后的两个实例中,左值引用而不是右值引用(如T&&
暗示的那样,这种理解是正确的吗?)已被记录为传递给foo。
如果上述理解是正确的,那么为什么将返回值指定为T&&
?
答案 0 :(得分:0)
之间有区别
void f1(int&& a) {}
template<class T>
void f2(T&& a) {}
第一个版本是定义f1
来处理rvalues。另一方面,第二个版本是一个模板函数,它接受一个通用(或某些引用,转发)引用作为其参数。
要了解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
。
在这个主题上,Arthur O&#39; Dwyer在CppCon2016上有一个really nice talk。也许您可以查看它以了解模板类型扣除规则,这将有助于您澄清std::forward
行为。