Поскольку предыдущие ответы исчерпывающе охватывали теорию, стоящую за категориями значений, я хотел бы добавить еще одну вещь: вы можете поиграть с ней и проверить ее.
Для некоторых практических экспериментов с категориями значений вы можете использовать спецификатор 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));
Смешанные категории становятся скучными, когда вы выяснили основную категорию.
Чтобы увидеть больше примеров (и экспериментов), посмотрите следующую ссылку в проводнике компилятора . Не читайте сборку. Я добавил много компиляторов, чтобы убедиться, что он работает на всех распространенных компиляторах.