简体   繁体   English

C ++通用引用。 为什么右值引用变成左值?

[英]C++ universal references. Why rvalue reference becomes lvalue?

Here's the code that troubles me 这是困扰我的代码

‍‍‍‍‍#include <iostream>

#include "DataItem.h"


void testRef( const int & param )
{
    std::cout << "Lvalue reference" << std::endl;
}

void testRef( int && param )
{
    std::cout << "Rvalue reference" << std::endl;

    // Here's the thing I can't get. Why param is lvalue reference here??
    testRef( param );
}


template<class T>
void func( T && param )
{
    testRef( std::forward<T>( param ) );
}


int main2() 
{
    int a = 12;
    func( a );

    std::cout << "=================" << std::endl;

    func( 14 );

    std::cout << "=================" << std::endl;

    return 0;
}

When I call testRef() in testRef( int && param ) I presume that as far as param is rvalue reference than ravalue function will called (and yes, eternal recursion will happen). 当我在testRef( int && param )调用testRef() ,我认为就param是右值引用而言,将调用ravalue函数(是的,将发生永恒递归)。 But lvalue function is called. 但是左值函数被调用。 Why? 为什么?

Think about it this way, you used std::forward<T> in func , so likewise, to make sure the parameter is forwarded as an Rvalue reference, you have to do the same in the recursive function: 考虑一下这种方式,您在func使用了std::forward<T> ,因此,要确保将参数作为Rvalue引用转发,您必须在递归函数中执行相同的操作:

void testRef(int && param)
{
    std::cout << "Rvalue reference" << std::endl;

    // Here's the thing I can't get. Why param is lvalue reference here??
    testRef( param );

    testRef(std::forward<int &&>(param)); // now it will stay an Rvalue reference
    testRef(std::move(param)); // make it an Rvalue reference
}

The reason we need std::forward or std::move is because param is of type int&& which is an lvalue (ie an rvalue reference parameter is an lvalue expression when you use it). 我们之所以需要std::forwardstd::move的原因是, param的类型为int&& ,这是一个左值(即,当使用右值引用参数时,它是一个左值表达式)。

Behind the scenes these templates will eventually perform a static_cast<int &&> which yields an xvalue expression (which is also classified as an rvalue expression.) An xvalue expression binds to rvalue reference parameters. 在后台,这些模板最终将执行static_cast<int &&> ,从而产生xvalue表达式(也被分类为rvalue表达式。)xvalue表达式绑定到rvalue参考参数。

This can be seen by looking at Clang's syntax tree for the following function: 通过查看Clang的语法树 ,可以看到以下功能:

             rvalue reference parameter (which binds to rvalue expressions)
             vvvvvvvvvvv
void testRef(int&& param)
{
    //std::move(param);

                        lvalue expression of type int&&
                        vvvvv
    static_cast<int &&>(param);
    ^^^^^^^^^^^^^^^^^^^^^^^^^^
    xvalue expression 
    (considered an rvalue expression which binds to rvalue reference parameters) 
}

Abstract syntax tree for the function above: 上面函数的抽象语法树:

TranslationUnitDecl
`-FunctionDecl <line:3:1, line:7:1> line:3:6 testRef 'void (int &&)'
  |-ParmVarDecl <col:14, col:21> col:21 used param 'int &&'
  `-CompoundStmt <line:4:1, line:7:1>
    `-CXXStaticCastExpr <line:6:5, col:30> 'int' xvalue static_cast<int &&> <NoOp>
      `-DeclRefExpr <col:25> 'int' lvalue ParmVar 0x55a692bb0a90 'param' 'int &&'

A shorthand way of explaining that a reference parameter becomes an lvalue would be to say that when it has a name (id-expression) it is an lvalue. 解释引用参数变为左值的一种简写方式是说,当它具有名称(id表达式)时,它就是左值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM