C++ 当你完善前进时,typename T变成T&;或T&&;,但当你不';t、 t是';这根本不是参考资料。怎么用?
我正在读关于完美转发的书,我学到了一些让我困惑的东西:C++ 当你完善前进时,typename T变成T&;或T&&;,但当你不';t、 t是';这根本不是参考资料。怎么用?,c++,templates,c++11,C++,Templates,C++11,我正在读关于完美转发的书,我学到了一些让我困惑的东西:当你试图实现完美转发时,你会这样做: template<class T> // If I were to call foo with an l-value int, foo would look void foo(T &&x); // like this: void foo(int& &&x) template//如果我用l值int调用foo,foo会 void foo(T&x);//如
当你试图实现完美转发时,你会这样做:
template<class T> // If I were to call foo with an l-value int, foo would look
void foo(T &&x); // like this: void foo(int& &&x)
template//如果我用l值int调用foo,foo会
void foo(T&x);//如下所示:voidfoo(int&&x)
然后我想,等等,这是否意味着如果我这样做:
template<class T> // If I were to call foo with an l-value int, foo would look
void foo(T x); // like this: void foo(int& x);
template//如果我用l值int调用foo,foo会
void foo(T x);//像这样:voidfoo(int&x);
但事实并非如此。foo看起来像这样:voidfoo(intx)代码>
我的问题:为什么在完美转发函数中,T会变成T&或T&&而在另一个函数中,T不是引用?有人能告诉我具体的规则吗?我需要一些澄清模板参数T
仅当出现在T&
表单的函数模板:
template void f(T x)
将T
推断为对象类型(并且x
是对象类型,因此通过值传递)
template void f(T&x)
将T
推断为对象类型(然后x
具有左值引用类型)
template void f(T&&x)
将推断T
为
- 左值引用(因此
x
由于引用折叠规则而具有左值引用类型)
- 或者作为对象类型(因此
x
具有右值引用类型)
如何在完美的转发功能中,T变成T&或T&,[…]
这是错误的T
成为参考类型L&
或对象类型R
,而不是参考R&
因此,形式T&
的函数参数变为
- 要么
L&
(因为向左值引用添加右值引用仍然是左值引用,就像add\u右值引用::type
仍然是L&
)
- 或者变成
R&
(因为add\u-rvalue\u-reference::type
是R&
)
这是因为定义类型推断的方式,它只与完美转发相关,因为传递右值引用时,std::forward()
的结果是右值,传递左值引用时是左值
但一般来说,当您没有引用开始时,您的T
不会被推断为引用类型(即a&
,无论a
可能是什么)。如果是这样的话,正如注释中正确指出的那样,就不可能编写一个按值获取参数的函数模板
特别是,您所指的引用折叠规则在C++11标准的第14.8.2.1/4段中有定义:
如果p是a
引用类型,P引用的类型用于类型推断如果P是对cv的右值引用
模板参数,并且参数是左值,在
类型扣除的地点。[示例:
模板int f(T&&);
模板int g(常数T&&);
int i;
int n1=f(i);//调用f(int&)
int n2=f(0);//调用f(int&&)
int n3=g(i);//错误:将调用g(const int&&),其中
//将右值引用绑定到左值
-[结束示例]
在推导模板参数时,一般需要考虑三种情况:
void foo(tx)
:这表示“通过值传递”。它总是根据需要推断出一个类型来传递值
void foo(T&x)
:这意味着“通过左值引用传递”。它总是推断出一个适当的类型以通过左值引用传递
void foo(T&&x)
:这意味着“通过引用传递”。它总是根据引用来推断适当的类型,可以是左值引用或右值引用
放松,放慢速度,呼吸
模板参数推导是您需要了解的核心机制,它不是完全琐碎的。当你说template void foo(T)
时,T
总是被推断为非引用类型
如果需要引用,则必须在其上放置&
:模板void foo(T&)
也会将T
推断为非引用类型,但foo
现在总是需要左值引用
最后一个魔法来自新的引用折叠规则。当您说template void foo(T&&)
时,可能会发生两件事:
- 使用右值调用
foo
,例如foo(Bar())
。然后将T
推导出为Bar
,foo
对Bar
进行右值引用,即Bar&
- 使用左值调用
foo
,例如条x;foo(x)代码>。现在,foo
唯一可以接受的就是左值引用。这要求将T
推断为Bar&
,因为T&&==Bar&&&&==Bar&
,这是由于折叠规则
只有这个最终模板才能同时接受左值和右值。这就是为什么它有时被称为“普遍参照”;但请记住,重要的不是引用,而是模板参数推断。使用std::forward
可以传递与接收到的值类别相同的参数。为什么也可能有用。如果模板void foo(T)
可以推断T=int&template <class T> int f(T&&);
template <class T> int g(const T&&);
int i;
int n1 = f(i); // calls f<int&>(int&)
int n2 = f(0); // calls f<int>(int&&)
int n3 = g(i); // error: would call g<int>(const int&&), which
// would bind an rvalue reference to an lvalue