为什么r值变成l值?

Ale*_*sky 1 c++

由于一般问题“如何std::forward工作”太复杂,我决定从一个特定示例的问题开始:

#include <utility>
#include <iostream>

namespace
{
    void foo(const int&)
    {
        std::cout << "const l-value" << std::endl;
    }

    void foo(int&)
    {
        std::cout << "l-value" << std::endl;
    }

    void foo(int&&)
    {
        std::cout << "r-value" << std::endl;
    }

    template <typename T>
    void deduce(T&& x)
    {
        //foo(std::forward<T>(x));
        foo(x);
    }
}

int main()
{
    deduce(1);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出:

l-value
Run Code Online (Sandbox Code Playgroud)

为什么?

我们传递 r 值,并且 的参数deduce是 r 值,对吧?为什么foo(int&)叫?

当我直接打电话时

foo(1);
Run Code Online (Sandbox Code Playgroud)

它打印r-value。里面什么时候变成l值了deduce

编辑1

如果我foo2在上面的代码中添加:

void foo2(int&& val)
{
    static_assert(std::is_same_v<decltype(val), int&&>);

    foo(val);
}
Run Code Online (Sandbox Code Playgroud)

然后从 main 调用它

foo2(1);
Run Code Online (Sandbox Code Playgroud)

l-value已打印但不r-value符合我的预期。

因此,正如评论和答案中提到的,val是 左值,因为它是一个命名变量,如果将其声明为int&&or并不重要int&。这是我以前不知道的。

use*_*522 10

每个人在介绍这一点时似乎都会感到困惑的是,值类别不是对象、变量或其他实体的属性。它不是类型或任何东西的一部分,这使得它令人困惑,因为我们还讨论左值引用右值引用,它们是与值类别不同的​​概念。值类别只是单个表达式的属性。

像or这样的id 表达式,命名变量,始终是左值表达式,无论命名变量具有什么类型,无论它是引用还是局部/全局变量、函数参数或模板参数等因此,命名右值引用类型变量的表达式仍然是左值表达式。xval

表达式的第二种属性,即类型,已删除引用。因此,表达式x(or val) 的值类别是左值,其类型是,尽管名为(or )的变量int的类型是(并且没有任何值类别)。xvalint&&

像这样所选函数std::forward<T>(x)的返回类型是右值引用的函数调用表达式是 xvalue 表达式(一种右值表达式)。再说一次,表达式的类型始终是非引用的,这里是int

有关每种表达式的值类别的完整列表,请参阅https://en.cppreference.com/w/cpp/language/value_category中的列表。

  • @AlexeyStarinsky https://eel.is/c++draft/basic#pre-3 (3认同)
  • @AlexeyStarinsky 我认为在这里说“成为”没有帮助。重点是值类别不是对象的属性。当对象传递给函数时,它并不像对象发生任何变化。“1”只是一个表达式,“x”是另一个不相关的表达式。前者是临时物化后的右值表达式或x值表达式,后者是左值表达式。两者之间没有任何联系。您使用前者作为名为“x”的函数参数的参数是无关紧要的。 (2认同)