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

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

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

这个测试用例应该有效,但令我惊讶的是(对我来说),添加两个 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 + jprvalue expression,

A prvalue ("pure rvalue") expression is an expression that does not have identity and can be moved from.

a + b, a % b, a & b, a << b, and all other built-in arithmetic expressions;

不是 xvalue,

An xvalue ("expiring value") expression is an expression that has identity and can be moved from.

并且 decltype specifier 对 prvalue 产生 T,而不是 T&&

a) if the value category of expression is xvalue, then decltype yields T&&;
b) if the value category of expression is lvalue, then decltype yields T&;
c) if the value category of expression is prvalue, then decltype yields T.

你可以通过 std::move:

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 deduces the type based on the value category, not based on what reference type 值将 绑定到 :

1) if the value category of expression is xvalue, then decltype yields T&&;
2) if the value category of expression is lvalue, then decltype yields T&;
3) if the value category of expression is prvalue, then decltype yields 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 不是右值引用,但它绑定到一个.