为什么"decltype(i+j)"的结果不是右值引用?

Why is the result of "decltype(i+j)" not an rvalue reference?

本文关键字:引用 decltype i+j 为什么 结果      更新时间:2023-10-16

我正在尝试为产生右值的操作提供一个简单的示例。

这个测试用例应该有效,但令人惊讶的是(对我来说),添加两个int的结果不是右值(引用)。我在这里错过了什么?

void test(int i, int j)
{
    // this assert should pass, but fails:
    static_assert(std::is_same<decltype(i + j), int&&>(), "i + j should be a rvalue"); 
    // this assert passed, but should fail:
    static_assert(std::is_same<decltype(i + j), int>(), "this assert should fail...");
}

i + j 是一个 prvalue 表达式,

prvalue("纯右值")表达式是没有标识并且可以从中移动的表达式。

A + B、A % B、A

& B、A <<B 以及所有其他内置算术表达式;

不是x值,

xvalue("过期值")表达式是具有标识并且可以从中移动的表达式。

并且 decltype 说明符产生 prvalue 的 T,而不是 T&& .

a) 如果表达式的值类别是 xvalue,则 decltype 产生 T&&;
b) 如果表达式的值类别是左值,则 decltype 产生 T&;
c) 如果表达式的值类别是 prvalue,则 decltype 产生 T。

你可以通过std::move使其成为xvalue:

static_assert(std::is_same<decltype(std::move(i + j)), int&&>(), "std::move(i + j) is a xvalue then this static_assert won't fail"); 

根据@songyuanyao的回答,我注意到我的错误是检查错误的东西:我的目的是检查i+j的结果是否会绑定到右值引用,但我检查了它是否右值引用。

decltype 根据值类别推断类型,而不是基于绑定到引用类型

1)如果表达式的值类别为xvalue,则decltype得到T&&;
2)如果表达式的值类别为lvalue,则decltype得到T&;
3)如果表达式的值类别为prvalue,则decltype产生T

如列表中所示,自 C++11 以来,rvalues在最低级别上不作为单独的类别存在。它们现在是一个包含prvaluesxvalues的复合类别。书面问题询问表达式是否为rvalue reference并检查它是否为xvalue

从上面的列表中,很明显i+j是一个 prvalue ,因此第三种情况适用。这就解释了为什么decltype(i + j)int而不是int&&xvaluesprvalues绑定到右值引用。

因此,通过检查i+j是否绑定到lvalue referencervalue reference确认它确实绑定到rvalue reference

void foo(const int& f)
{
    std::cout << "binds to lvalue reference" << std::endl;
}
void foo(int&& f)
{
    std::cout << "binds to rvalue reference" << std::endl;
}
void test(int i, int j)
{
    foo(i); // lvalue -> lvalue ref
    foo(std::move(i)); // xvalue -> rvalue ref 
    // (std::move converts the argument to a rvalue reference and returns it as an xvalue)
    foo(i + j); // prvalue -> rvalue ref
}

结论:i+j不是右值引用,但它绑定到一个。