expression - синтаксическая конструкция, которая состоит из идентификаторов и литералов, соединенных операторами и скобочками все инструкции бывают либо

  • expressions
  • declaration (using-и), должны быть в блок скоупе или в глобальной области
  • control statement - (ифы, форы, вайлы)

lvalue/rvalue - характеристика экспрешена в си было так, что lvalue - то, что может стоять слева от =, rvalue - всё, что не lvalue в C++ lvalue это то, что лежит в памяти glvalue - то, что лежит в памяти (lvalue) или имеет временное расположение (xvalue), rvalue - это те, которые не имеют расположения в памяти (prvalue) или имеют временное расположение (xvalue)

(x=y)=z при (x=y) возвращается ссылка, на то, что получилось (х), lvalue результаты операторов присваивания - lvalue lvalue можно что-то присваивать rvalue a++; lvalue ++a; возвращаемый тип префиксного инкремента это ссылка на объект ++a++ по стандарту постфиксные операции приоритетнее, поэтому так нельзя писать

результатом тернарного оператора будет lvalue только если оба возвращаемых объекта lvalue, иначе в любом случае rvalue тип результата тернарного оператора вычисляется на этапе компиляции

операторы, возвращающие lvalue: разыменование, префиксный инкремент/декремент, присваивание, []

оператор запятая возвращает правое значение (a,b) = 1 тоже самое что b = 1; delete p,pp == delete p delete (p,pp) == delete pp

результат sizeof() это constexpr

имя переменной вступает в действие сразу после = т.е. int x = x; - корректно (== int x;) однако это UB, тк имя то действительное, но объект lifetime не начал

void func(int a) = delete; запрещает вызов функции с такими аргументами (даёт CE)

к rvalue своих типов данных можно присваивать, если не определить это иначе (справа от перегрузки добавить &)

если есть метод, который возвращает ссылку на поле, то его стоит пометить &, чтоб вызывался только от lvalue, чтоб избежать dangling references int& x = S{}.x - UB

вектор буль - пример того, когда rvalue что-то нужно присваивать. оператор[] вектора буль возвращает новый временный объект (rvalue - ему не соответствует никакая переменная в памяти), присваивание к которому изменяет объект вектора

assert() - function-like макрос, который вызывает std::abort в runtime, если условие ложно в релиз билде исчезает static_assert(constexpr) - функция, которая в compile time кидает CE, если ей передали false

(3+2)++ - некоректно, потому что инкремент можно вызывать только у lvalue, а результат + - rvalue

formal definitions of lvalue and rvalue

lvalue и rvalue - виды экспрешенов, а не типов!!! каждый экспрешен обладает 2 независимыми свойствами - тип и вид value int&& - никакое не value, это тип

lvalue

  • любая переменная, не важно какого типа
  • строковый литерал (“abc”)
  • все операторы присваивания над фундаментальными типами
  • префиксный инкремент/декремент над фундаментальными типами
  • если после разыменования получается фундаментальный тип
  • если получается фундаментальный тип после []
  • результат вызова функции - T&
  • результат каста, если каст был к T&

вид value результата оператора запятой - вид value её правой части вид value результата тернарного оператора: обе части lvalue - lvalue одна из частей rvalue - rvalue обе части rvalue - rvalue тк в compile time нужно решить вид всего выражения, поэтому берется “худший случай”

rvalue

  • литерал (‘a’, 42, 2.0f, true)
  • все арифметические операторы и операторы сравнения над фундаментальными типами
  • постфиксный инкремент/декремент над фундаментальными типами
  • унарный & (&x)
  • результат вызова функции T или T&&
  • результат каста, если каст был к T либо к T&&

T&& - такая ссылка, которая ведёт себя как обычная ссылка, но если её вернуть из функции, то это будет считаться rvalue переменные типа T&& - всё равно lvalue

lambdas move semantics