为什么这个右值引用仅适用于整数而不适用于结构

Sai*_*000 1 c++

#include <iostream>

//option 1
struct Obj
{
    auto f(int&& x) { printf("&&\n"); }
    auto f(int const& x) { printf("const&\n"); }
    
    auto g() const { return int{}; } 
    const auto h() const { return int{}; } 
};

//option 2
struct Obj2
{
    auto f(Obj&& x) { printf("&&\n"); }
    auto f(Obj const& x) { printf("const&\n"); }

    auto g() const { return Obj{}; } 
    const auto h() const { return Obj{}; } 
};

int main()
{
    {
        int x;
        Obj obj;
        obj.f(obj.g()); // prints "&&"
        obj.f(obj.h()); // prints "&&"
    }
    printf("\n");
    {
        Obj x;
        Obj2 obj;
        obj.f(obj.g()); // prints "&&"
        obj.f(obj.h()); // doesn't print "&&" ?! Why?
    }
}
Run Code Online (Sandbox Code Playgroud)

据我所知,如果您从函数的返回值中设置一个值,则该函数的返回值将是一个右值。

auto x = foo(y); // x always receives an rvalue, right?
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,显然这并不总是发生。如果 y 是 int ,则它可以工作(选项 1),但如果 y 是结构体,则 g 的返回值仍然是右值,但 h 则不是。为什么?为什么它适用于整数而不适用于结构?

我正在使用 c++20 和 gcc 13.2

Hol*_*Cat 5

[expr.type]/2

\n
\n

如果纯右值最初的类型为 \xe2\x80\x9ccv T\xe2\x80\x9d,其中 T 是 cv 未限定的非类、非数组类型,则在任何进一步的操作之前,表达式的类型将调整为 T分析。

\n
\n

换句话说,如果您const T按值返回,并且T既不是类也不是数组,则const会被静默删除。

\n

当您有 const 右值时,它不能绑定到非 const T &&,但可以绑定到const T &,以便改用重载。(非常量右值可以同时绑定到T &&const T &,并且前者优先。)

\n

因此,返回 const 值几乎总是一个错误,因为它阻止您移动对象,默默地强制复制。在 C++98 中,它被用来阻止人们分配给右值(移动语义不是一回事),但现在您可以通过 -&限定赋值运算符来实现相同的效果。

\n

  • 哇,你们真快。谢谢@HolyBlackCat,“默默地强制复制”这正是我的问题,它适用于原始类型,然后适用于嵌套模板,它适用于 op=(const &amp;) 并且不知道为什么:) (2认同)