Почему результат "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...");
}
Ответы
Ответ 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, но привязывается к.