为啥 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&amp;&amp; 的参数是左值时,P 将被推断为参数的类型加上&amp; 附加。所以你得到int &amp; &amp;&amp;Pint&amp;。如果参数是一个右值,那么 P 将被推导为仅参数的类型,所以你得到一个 int&amp;&amp; 参数,如果你会通过,Pint,例如直接0

int&amp; &amp;&amp; 将折叠为int&amp;(这是一个语义视图 - 语法上int&amp; &amp;&amp; 是非法的。但是当U 是模板参数或引用类型int&amp; 的typedef 时说U &amp;&amp;,那么U&amp;&amp; 仍然是int&amp; 类型——即两个引用“折叠”到一个左值引用)。这就是t 的类型为int&amp; 的原因。

【讨论】:

哦,废话,使用 r 值引用会复杂很多。所以我需要编写模板代码,以便它适用于 r-value 和 l-value 引用? :-/ @Let:嗯,你转发正确,有什么问题? @Fred 问题是这段代码不适用于 r-value 引用(和临时),即使接口提供了 r-value 引用。 @Let:它不起作用,因为f 只接受左值。如果您想将 g 限制为仅接受左值,请参阅下面我自己的答案。 @Let: 不,g(f, 10) 确实 调用f(10),这是不可能的,因为int&amp; 不绑定到诸如10 之类的右值。由于10 是一个右值,T&amp;&amp; 被推断为int&amp;&amp;,因此t 绑定到一个初始化为10 的临时对象t 本身,就像所有其他名称,是一个左值,因此它可以绑定到int&amp; 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&?的主要内容,如果未能解决你的问题,请参考以下文章

为啥需要绑定 `T: 'a` 来存储引用 `&'a T`?

列表初始化是不是将原子初始化为零?

新分配的 std::vector<int> 元素是不是初始化为 0?

嵌套模板的模板模板别名?

模棱两可的模板实例化

为啥 Int8.max &+ Int8.max 等于“-2”?