我正在学习模板,尤其是std::forward
;当我检查其实现时,它在其参数列表中使用了另一个类模板std::remove_reference
:
template<class _Ty>
_Ty&& forward(typename remove_reference<_Ty>::type& _Arg)
{// forward an lvalue as either an lvalue or an rvalue
// ...
}
btw:为了清楚起见,我删除了一些内容,例如内联,constexpr,NO_EXCEPT和该函数的主体
我了解了当模板参数是指针(_Ty*
),引用(_Ty
&),通用引用(_Ty
)时如何推导类型以及其类型所在本身(_Ty
)。在这种情况下,它是一个引用,但在其前面添加了removed_reference<_Ty>::type
; _Ty
和引用通过对remove_reference
的调用来拆分。编译器如何确定_Ty
的类型?
函数模板必须使用传递给函数的参数来确定模板参数(当未在函数调用中显式定义它们时),但是在这种情况下,remove_reference也是需要确定类型的类模板。 _Ty
也是如此。对我来说,这几乎像个陷阱22,因为std::forward
需要使用其函数参数来找出_Ty
,但是其函数参数std::remove_reference<_Ty>
必须已经知道_Ty
是什么。这一切告诉我,我对模板的工作方式有一个错误的了解,但是我不知道在哪里。
答案 0 :(得分:4)
编译器如何确定_Ty的类型?
不是。 std::forward
用于显式提供的类型。它是通过接受类型为std::forward
的{{1}}的函数参数来实现的,其中typename remove_reference<_Ty>::type
在non-deduced context中。编译器不能推断出它。
转发参考的典型用法如下:
_Ty
严格来说,template<typename T>
void foo(T&& t) {
std::forward<T>(t);
}
只是对以上std::forward
进行强制转换的语法糖。 reference collapsing确实发挥了所有魔力,但是对T&&
的裸露投递并没有传达与命名运算符一样清晰的转发意图。这就是T&&
存在的原因。
答案 1 :(得分:3)
它不能演绎。这就是为什么当您使用public abstract class test {
int count;
public test(){
count();
count();
System.out.println("test" + this.count);
}
abstract void count();
}
public class derive extends test{
int count;
public derive(){
System.out.println("derive");
}
@Override
public void count(){
count++;
}
}
public static void main(String[] args) {
derived o = new derived();
}
时,必须为其指定模板参数:
std::forward
这与std::forward<T>(t);
相反,后者确实可以得出结论,并且通常这样使用:
std::move
答案 2 :(得分:2)
std::move(t);
如何推断std::forward
的类型?
_Ty
没有一种类型。 Ty
是一种类型(模板参数)。编译器不推断类型。
编译器如何确定
Ty
的类型?
必须显式传递模板参数。
如果推断出类型,则:
_Ty
将传递一个左值,因为template<class T>
void foo(T&& t) {
bar(std::forward(t));
}
是一个左值。但是我们想传递一个右值,因为t
是右值引用。由于推论起反作用,因此使用t
技巧将其禁用,我们必须正确编写:
remove_reference<_Ty>::type&