提问者:小点点

转发引用不是推导成R值引用吗?[副本]


我有一个关于转发推荐信的具体问题。(我认为)我理解R值引用和std::move,但理解转发引用有困难:

#include <iostream>
#include <utility>

template <typename T> class TD; // from "Effective Modern C++"

void consume(const int &i) { std::cout << "lvalue\n"; }
void consume(int &&i)      { std::cout << "rvalue\n"; }

template <typename T>
void foo(T&& x) {
//    TD<decltype(x)> xType; - prints int&&
    consume(x);
}

int main() {
    foo(1 + 2);
}

tint,这很好。如果xint&类型,为什么它打印“lvalue”,而我们需要std::forward?我的意思是,从int&&const int&的转换在哪里?


共2个答案

匿名用户

呼叫:

consume(x);

将始终选择consumer()的lvalue引用重载,因为表达式x是一个lvalue。这与x的推导类型无关。

但是,通过调用consumer()作为:

consume(std::forward<T>(x));

如果传递给foo()(即包装函数)的参数的值类别是一个rvalue,它将选择rvalue引用重载-即,它将该值类别传播到嵌套调用。

匿名用户

类型和值类别是两个独立的东西。x的类型是int&,但x是变量的名称,x是一个lvalue表达式,它不能绑定到int&(但可以绑定到const int&)。

以下表达式是lvalue表达式:

  • 变量、函数、模板参数对象(自C++20起)或数据成员的名称,无论类型如何,如std::cin或std::endl。即使变量的类型是rvalue引用,由其名称组成的表达式也是lvalue表达式;

std::forward用于根据转发引用参数的原始值类别将操作数转换为rvalue或lvalue。这意味着,当lvalueint传递给foo时,t被推导为int&,那么std::forward(x)将是lvalue表达式;当rvalueint传递给foo时,t被推导为int,那么std::forward(x)将是rvalue表达式。因此std::forward可用于保留原始转发引用参数的值类别。