为啥 T&& 实例化为 int&?
Posted
技术标签:
【中文标题】为啥 T&& 实例化为 int&?【英文标题】:Why is T&& instantiated as int&?为什么 T&& 实例化为 int&? 【发布时间】:2010-12-01 18:29:26 【问题描述】:谁能解释一下为什么会编译以及为什么t
会以int&
结束?
#include <utility>
void f(int& r)
++r;
template <typename Fun, typename T>
void g(Fun fun, T&& t)
fun(std::forward<T>(t));
int main()
int i = 0;
g(f, i);
我在 GCC 4.5.0 20100604 和 GDB 7.2-60.2 上看到了这个
【问题讨论】:
【参考方案1】:由于完美转发,当P&&
的参数是左值时,P
将被推断为参数的类型加上&
附加。所以你得到int & &&
和P
是int&
。如果参数是一个右值,那么 P
将被推导为仅参数的类型,所以你会得到一个 int&&
参数,如果你会通过,P
是 int
,例如直接0
。
int& &&
将折叠为int&
(这是一个语义视图 - 语法上int& &&
是非法的。但是当U
是模板参数或引用类型int&
的typedef 时说U &&
,那么U&&
仍然是int&
类型——即两个引用“折叠”到一个左值引用)。这就是t
的类型为int&
的原因。
【讨论】:
哦,废话,使用 r 值引用会复杂很多。所以我需要编写模板代码,以便它适用于 r-value 和 l-value 引用? :-/ @Let:嗯,你转发正确,有什么问题? @Fred 问题是这段代码不适用于 r-value 引用(和临时),即使接口提供了 r-value 引用。 @Let:它不起作用,因为f
只接受左值。如果您想将 g
限制为仅接受左值,请参阅下面我自己的答案。
@Let: 不,g(f, 10)
确实不 调用f(10)
,这是不可能的,因为int&
不绑定到诸如10
之类的右值。由于10
是一个右值,T&&
被推断为int&&
,因此t
绑定到一个初始化为10 的临时对象。t
本身,就像所有其他名称,是一个左值,因此它可以绑定到int& r
。修改++r
可以在g
中观察到,只需将t
打印到控制台就可以看到。 名称始终是左值,即使是右值引用的名称。这样就清楚了吗?【参考方案2】:
如果出于某种原因您真的想专门绑定到左值或右值,请使用元编程:
#include <type_traits>
template <typename T>
typename std::enable_if<std::is_lvalue_reference<T&&>::value, void>::type
fun(T&& x)
std::cout << "lvalue argument\n";
template <typename T>
typename std::enable_if<std::is_rvalue_reference<T&&>::value, void>::type
fun(T&& x)
std::cout << "rvalue argument\n";
int main()
int i = 42;
fun(i);
fun(42);
【讨论】:
以上是关于为啥 T&& 实例化为 int&?的主要内容,如果未能解决你的问题,请参考以下文章