Подтвердить что ты не робот

Почему результат "decltype (i + j)" не является ссылкой на rvalue?

Я пытаюсь привести простой пример для операции, которая приводит к rvalue.

Этот тестовый пример должен был работать, но на удивление (для меня) результат добавления двух int не является 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...");
}
4b9b3361

Ответ 1

i + j - выражение prvalue,

Выражение prvalue ( "pure rvalue" ) - выражение, которое не имеет идентификатора и может быть перенесено из.

a + b, a% b, a и b, a < b и всех других встроенных арифметических выражений;

не xvalue,

Выражение xvalue ( "expired value" ) является выражением, которое имеет идентификатор и может быть перемещено из.

И спецификатор decltype дает T для prvalue, а не T&&.

a) если категория значений выражения равна xvalue, тогда decltype дает T & &;
б) если категория значений выражения равна lvalue, то decltype дает T &;
c) если категория значений выражения является prvalue, тогда decltype дает T.

Вы можете сделать его значением xvalue на 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"); 

Ответ 2

Основываясь на @songyuanyao Отвечать, я заметил, что моя ошибка заключалась в проверке неправильного: мое намерение состояло в том, чтобы проверить, будет ли результат i+j привяжите к ссылку на rvalue, но я проверил, является ли ссылкой rvalue.

decltype выводит тип, основанный на категория ценности, не основанная на том, что тип ссылки значение будет привязываться к

1), если категория значений выражения xvalue, тогда decltype дает T&&;
2) если категория значений выражения lvalue, то decltype дает T&,
3) если категория значений выражения prvalue, то decltype дает T.

Как показано в списке, , поскольку С++ 11, rvalues не существуют как отдельная категория на самом низком уровне. Теперь они представляют собой составную категорию, содержащую как prvalues, так и а также xvalues. Вопрос, как написано, спрашивает, является ли выражение rvalue reference и проверяет, является ли это xvalue.

Из приведенного выше списка видно, что i+j является prvalue, поэтому применяется третий случай. Это объясняет, почему decltype(i + j) есть int, а не int&&. Оба xvalues и prvalues привязываются к rvalue-ссылкам.

Итак, проверяя, привязан ли 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 не ссылка rvalue, но привязывается к.