Что такое rvalues, lvalues, xvalues, glvalues ​​и prvalues? - PullRequest
1252 голосов
/ 30 августа 2010

В C ++ 03 выражением является либо значение r , либо значение .

В C ++ 11 выражение может быть:

  1. Rvalue
  2. именующий
  3. xvalue
  4. glvalue
  5. prvalue

Две категории стали пятью категориями.

  • Что это за новые категории выражений?
  • Как эти новые категории относятся к существующим категориям rvalue и lvalue?
  • Являются ли категории rvalue и lvalue в C ++ 0x такими же, как и в C ++ 03?
  • Зачем нужны эти новые категории? Неужели боги WG21 просто пытаются сбить нас с толку простых смертных?

Ответы [ 11 ]

3 голосов
/ 14 февраля 2019

Поскольку предыдущие ответы исчерпывающе охватывали теорию, стоящую за категориями значений, я хотел бы добавить еще одну вещь: вы можете поиграть с ней и проверить ее.

Для некоторых практических экспериментов с категориями значений вы можете использовать спецификатор decltype . Его поведение явно различает три категории основных значений (xvalue, lvalue и prvalue).

Использование препроцессора спасает нас от набора текста ...

Первичные категории:

#define IS_XVALUE(X) std::is_rvalue_reference<decltype((X))>::value
#define IS_LVALUE(X) std::is_lvalue_reference<decltype((X))>::value
#define IS_PRVALUE(X) !std::is_reference<decltype((X))>::value

Смешанные категории:

#define IS_GLVALUE(X) IS_LVALUE(X) || IS_XVALUE(X)
#define IS_RVALUE(X) IS_PRVALUE(X) || IS_XVALUE(X)

Теперь мы можем воспроизвести (почти) все примеры из cppreference для категории значений .

Вот несколько примеров с C ++ 17 (для краткой static_assert):

void doesNothing(){}
struct S
{
    int x{0};
};
int x = 1;
int y = 2;
S s;

static_assert(IS_LVALUE(x));
static_assert(IS_LVALUE(x+=y));
static_assert(IS_LVALUE("Hello world!"));
static_assert(IS_LVALUE(++x));

static_assert(IS_PRVALUE(1));
static_assert(IS_PRVALUE(x++));
static_assert(IS_PRVALUE(static_cast<double>(x)));
static_assert(IS_PRVALUE(std::string{}));
static_assert(IS_PRVALUE(throw std::exception()));
static_assert(IS_PRVALUE(doesNothing()));

static_assert(IS_XVALUE(std::move(s)));
// The next one doesn't work in gcc 8.2 but in gcc(trunk). Clang 7.0.0 and msvc 19.16 are doing fine.
static_assert(IS_XVALUE(S().x)); 

Смешанные категории становятся скучными, когда вы выяснили основную категорию.

Чтобы увидеть больше примеров (и экспериментов), посмотрите следующую ссылку в проводнике компилятора . Не читайте сборку. Я добавил много компиляторов, чтобы убедиться, что он работает на всех распространенных компиляторах.

...