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

问题描述 投票:2回答:1

这是困扰我的代码

‍‍‍‍‍#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;
}

当我在testRef()中调用testRef( int && param )时,我认为只要param是rvalue引用而不是ravalue函数将被调用(并且是的,将发生永久递归)。但是调用左值函数。为什么?

c++ rvalue type-deduction
1个回答
3
投票

想一想,你在std::forward<T>中使用了func,同样,为了确保参数作为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
}

我们需要std::forwardstd::move的原因是因为paramint&&类型,它是一个左值(即当你使用它时,右值参考参数是一个左值表达式)。

在幕后,这些模板最终将执行static_cast<int &&>,它产生一个xvalue表达式(也被归类为rvalue表达式。)xvalue表达式绑定到rvalue引用参数。

通过查看Clang's syntax tree可以看出以下函数:

             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) 
}

上述函数的抽象语法树:

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 &&'

解释参考参数变为左值的简写方式是,当它具有名称(id-expression)时,它是左值。

© www.soinside.com 2019 - 2024. All rights reserved.