web-dev-qa-db-ja.com

「decltype(i + j)」の結果が右辺値参照ではないのはなぜですか?

右辺値になる操作の簡単な例を考え出そうとしています。

このテストケースは機能するはずでしたが、驚くべきことに(私にとって)、2つのintsを追加した結果は右辺値(参照)ではありません。ここで何が欠けていますか?

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...");
}
17
anderas

i + jprvalue式

Prvalue( "pure rvalue")式は、IDを持たず、から移動できる式です。

a + b、a%b、a&b、a << b、およびその他すべての組み込み算術式。

xvalue ではありません、

Xvalue( "expiring value")式は、アイデンティティを持ち、そこから移動できる式です。

そして decltype specifier は、T&&ではなくprvalueに対して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"); 
33
songyuanyao

@songyuanyaoの Answer に基づいて、私の間違いが間違ったことをチェックしていることに気づきました。私の意図は、_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であることが明らかであるため、3番目のケースが適用されます。これは、decltype(i + j)intであり、_int&&_ではない理由を説明しています。 xvaluesprvaluesbind to右辺値参照の両方。

したがって、_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
}
_

結論:_i+j_はnot右辺値参照、しかし、それは1つにバインドします

5
anderas