为什么obj.i和std :: forward <int>(obj.i)的类型不同?

时间:2016-05-10 14:21:24

标签: c++11

根据Is a member of an rvalue structure an rvalue or lvalue?

如果E1是左值,那么E1.E2是左值,只有当该参数绑定到右值时,才将其参数转发到右值。在下面的函数void foo(Obj &&obj)中,obj是左值,因此obj.i是左值,为什么std::forward<int>(obj.i)是左值?

class Obj
{
    public:
        int i;
};


void foo(int &i)
{
    cout<<"foo(int&)"<<endl;
}

void foo(int &&i)
{
    cout<<"foo(int&&)"<<endl;
}

void foo(Obj &&obj)
{
    foo(std::forward<int>(obj.i));
    foo(obj.i);
}

int main()
{
    Obj obj;
    foo(std::move(obj));
    return 0;
}

输出

foo(int&&)
foo(int&)

3 个答案:

答案 0 :(得分:0)

  

下面的函数void foo(Obj&amp;&amp; obj):

     

obj是左值,所以obj.i是左值,

嗯,您是否在函数proto中将obj声明为右值参考,然后坚持认为它是左值

答案 1 :(得分:0)

根据std::forward的规范,返回类型很简单,应用于模板类型的右值引用。因此返回类型std::forward<int>int&& - 以这种方式使用它与std::move具有完全相同的效果。

使用std::forward的常规方法是使用通用引用:

template<typename T>
void f(T&& val)
{
     other_func(std::forward<T>(val));
}

这适用于引用,因为在这种情况下左值引用的推导类型也是左值引用。在你的情况下,你是硬编码类型(到int)而不是推导它 - 如果使用上述模式,推导出的类型实际上是int&,而不是int

您会看到,如果您将foo(std::forward<int>(obj.i))更改为foo(std::forward<int&>(obj.i)),您将得到您期望的结果

答案 2 :(得分:0)

你实际上是在转发错误的东西。在这个功能中:

void foo(Obj &&obj)
{
    foo(std::forward<int>(obj.i));
    foo(obj.i);
}

obj有名字,所以它是左值。在这两种情况下,obj.i都是左值,只是在第一次将它明确地转换为右值时!当forward获得引用类型时,您会获得左值。当它获得非引用类型时,您将得到一个右值。你给它一个非引用类型,所以这里的forward相当于:foo(std::move(obj.i));这会让你更清楚为什么得到一个右值?

但是,您链接的问题是关于 rvalues 的成员。为此,您需要将obj本身转换为右值:

foo(std::move(obj).i);

此处,由于std::move(obj)是左值,std::move(obj).i也是左值。

无论如何,在通过非转发引用参数时使用forward有点奇怪。这是一个更一般的例子:

template <class O>
void foo(O&& obj) {
    foo(std::forward<O>(obj).i);
}

foo(obj);            // calls foo(int&)
foo(std::move(obj)); // calls foo(int&&)

在前一种情况下,std::forward<O>(obj)是左值,因为OObj&,这使得std::foward<O>(obj).i成为左值。在后一种情况下,它们都是左值。