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

and*_*ras 17 c++ rvalue decltype rvalue-reference c++11

我试图给出一个导致rvalue的操作的简单示例.

这个测试用例应该有效,但令人惊讶的是(对我而言),添加两个ints 的结果不是rvalue(引用).我在这里错过了什么?

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...");
}
Run Code Online (Sandbox Code Playgroud)

son*_*yao 33

i + j是一个prvalue表达式,

prvalue("纯rvalue")表达式是一个没有标识且可以从中移出的表达式.

a + b,a%b,a&b,a << b,以及所有其他内置算术表达式;

不是xvalue,

xvalue("expiring value")表达式是一个具有标识且可以从中移出的表达式.

decltype说明符产生Tprvalue,而不是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"); 
Run Code Online (Sandbox Code Playgroud)


and*_*ras 5

基于@ songyuanyao的答案,我注意到我的错误是检查错误的东西:我的意图是检查结果是否i+j绑定到右值引用,但我检查它是否右值引用.

decltype 基于值类别推断类型,而不是基于值将绑定到的引用类型:

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

如列表所示,自C++ 11以来,rvalues不存在于最低级别的独特类别.他们现在既含有复合类prvalues以及xvalues.写的问题询问表达式是否为a rvalue reference并检查它是否为a xvalue.

从上面的列表中可以清楚地看出i+j是a prvalue,所以第三种情况适用.这就解释了为什么decltype(i + j)int和不是int&&.双方xvaluesprvalues 绑定到右值引用.

因此,通过检查是否i+j绑定到一个lvalue reference或一个rvalue 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
}
Run Code Online (Sandbox Code Playgroud)

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