【问题标题】: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 上看到了这个

【问题讨论】:

    标签: c++ templates c++11 forwarding rvalue-reference


    【解决方案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);
    }
    

    【讨论】:

      猜你喜欢
      • 2011-07-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-04
      相关资源
      最近更新 更多