Выражения
Выражение — это последовательность операторов и их операндов, которая задаёт вычисление.
Вычисление выражения может дать результат (например, вычисление 2 + 2 даёт результат 4) и может иметь побочные эффекты (например, вычисление std::printf("%d", 4) выводит символ '4' на стандартный вывод).
Каждое выражение C++ характеризуется двумя независимыми свойствами: типом и категорией значения.
Общие сведения
- категории значений (lvalue, rvalue, glvalue, prvalue, xvalue(с C++11)) классифицируют выражения по их значениям
- порядок вычисления аргументов и подвыражений определяет порядок получения промежуточных результатов
Операторы
| Общие операторы | ||||||
|---|---|---|---|---|---|---|
| присваивание |
инкремент декремент | арифметические | логические | сравнения |
доступ к членам объекта | прочие |
|
|
|
|
|
|
| вызов функции |
a(...) |
||||||
| запятая | ||||||
a, b |
||||||
| условный оператор | ||||||
a ? b : c |
||||||
| Специальные операторы | ||||||
|
|
||||||
- приоритет операторов определяет порядок связывания операторов с их аргументами
- альтернативные записи представляют собой альтернативные способы написания некоторых операторов
- перегрузка операторов позволяет задать поведение операторов для пользовательских классов.
Преобразования
- стандартные преобразования неявные преобразования из одного типа в другой
-
const_castпреобразование -
static_castпреобразование -
dynamic_castпреобразование -
reinterpret_castпреобразование - явное преобразование преобразование с использованием обозначений операторов в стиле C и в функциональном стиле
- пользовательское преобразование позволяет задать преобразование из пользовательских классов
Выделение памяти
- оператор new выделяет память динамически
- оператор delete освобождает память динамически
Прочие
- константные выражения могут быть вычислены во время компиляции и использованы в контексте компиляции (аргументы шаблонов, размеры массивов и т. д.)
-
sizeof -
alignof -
typeid - выражение throw
Первичные выражения
Операндами любого оператора могут быть другие выражения или первичные выражения (например, в 1 + 2 * 3, операндами оператора + являются подвыражение 2 * 3 и первичное выражение 1).
Первичные выражения — это:
-
this - литералы (например,
2или"Hello, world") - идентификаторы, включая
- должным образом объявленные неопределённые идентификаторы (например,
nилиcout), - должным образом объявленные квалифицированные идентификаторы (например,
std::string::npos), и - идентификаторы, подлежащие объявлению в деклараторах
- должным образом объявленные неопределённые идентификаторы (например,
| (с C++26) |
| (с C++11) | |
| (с C++17) | |
| (с C++20) |
Любое выражение в скобках также классифицируется как первичное выражение: это гарантирует, что скобки имеют более высокий приоритет, чем любой оператор. Скобки сохраняют значение, тип и категорию значения.
Литералы
Литералы — это токены программы C++, которые представляют собой константные значения, встраиваемые в исходный код.
- целочисленные литералы — это десятичные, восьмеричные, шестнадцатеричные или двоичные числа целочисленного типа.
- символьные литералы — это отдельные символы типа
- char или wchar_t
| (с C++11) |
| (с C++20) |
- вещественные литералы — это значения типа float, double или long double
- строковые литералы — это последовательности символов типа
- const char[] или const wchar_t[]
| (с C++11) |
| (с C++20) |
- булевы литералы — это значения типа bool, а именно
trueиfalse
| (с C++11) |
Полные выражения
Составное выражение определяется следующим образом:
- Составным выражением для выражения является само это выражение.
- Составными выражениями для списка инициализации фигурными скобками или для списка выражений (возможно, в скобках) являются составные выражения для элементов соответствующего списка.
- Составными выражениями для инициализатора фигурными скобками или знаком равенства вида
=инициализирующее выражение являются составные выражения для инициализирующего выражения.
int num1 = 0;
num1 += 1; // Case 1: the constituent expression of `num += 1` is `num += 1`
int arr2[2] = {2, 22} // Case 2: the constituent expressions
// of `{2, 22}` are `2` and `22`
// Case 3: the constituent expressions of ` = {2, 22}`
// are the constituent expressions of `{2, 22}`
// (i.e. also `2` and `22`)Непосредственные подвыражения выражения E — это
- составные выражения для операндов
E
| (с C++14) |
| (с C++11) |
- любой вызов функции, который
Eнеявно вызывает, или - если
Eявляется вызовом функции или неявно вызывает функцию, составные выражения для каждого аргумента по умолчанию, используемого в вызове.
Подвыражение выражения E — это непосредственное подвыражение E или подвыражение непосредственного подвыражения E. Обратите внимание, что выражения, присутствующие в «теле функции» лямбда-выражений, не являются подвыражениями лямбда-выражения.(с C++11)
Полное выражение — это
| (с C++20) |
- декларатор простого объявления или инициализатора члена, включая составные выражения инициализатора,
- вызов деструктора, сгенерированного в конце жизни объекта, отличного от временного объекта, чья жизнь не была продлена, или
- выражение, которое не является подвыражением другого выражения и которое не является иначе частью полного выражения.
Если языковая конструкция определена таким образом, что она производит неявный вызов функции, то использование такой языковой конструкции считается выражением для целей данного определения. Преобразования, применяемые к результату выражения для удовлетворения требований языковой конструкции, в которой появляется выражение, также считаются частью полного выражения.
Для инициализатора выполнение инициализации сущности (включая вычисление инициализаторов членов по умолчанию агрегированного объекта)(с C++14) также считается частью полного выражения.
Выражения, потенциально подлежащие вычислению
| Выражение потенциально вычисляется, за исключением случаев
| (до C++11) | ||
| Следующие операнды являются невычисляемыми, они не вычисляются:
Выражение потенциально вычисляется, за исключением случаев
| (с C++11) |
Выражения со значениями, отбрасываемыми
Выражение со значением, отбрасываемым — это выражение, используемое только для побочных эффектов. Вычисленное из него значение отбрасывается. Такие выражения включают полное выражение любого выражения-оператора, левый операнд встроенного оператора запятой или операнд выражения-приведения, которое приводится к типу void.
Преобразования «массив в указатель» и «функция в указатель» никогда не применяются к значению, вычисленному выражением со значением, отбрасываемым. Преобразование lvalue в rvalue применяется тогда и только тогда, когда выражение является glvalue с квалификатором volatile и имеет один из следующих видов (требуется встроенный смысл, возможно, в скобках):
- выражение-идентификатор,
- выражение индексации массива,
- выражение доступа к члену класса,
- косвенное обращение,
- операция указателя на член,
- условное выражение, где второй и третий операнды являются одним из этих выражений,
- выражение с запятой, где правый операнд является одним из этих выражений.
Кроме того, если lvalue имеет тип класса с квалификатором volatile, требуется конструктор копирования с квалификатором volatile для инициализации полученного временного rvalue.
| Если выражение является не-void prvalue (после возможного преобразования lvalue в rvalue), происходит создание временного объекта. Компиляторы могут выводить предупреждения, когда выражение, отличное от приведения к void, отбрасывает объявленное значение | (с C++17) |
Эквивалентность выраженийНесколько выражений
| (с C++20) |
Отчеты об ошибках
Следующие отчеты об ошибках, изменяющие поведение, были применены ретроактивно к ранее опубликованным стандартам C++.
| DR | Применимо к | Поведение, как опубликовано | Правильное поведение |
|---|---|---|---|
| CWG 1054 | C++98 | присваивание значения переменной volatile может привести к ненужному чтению из-за преобразования lvalue- в rvalue, применяемого к результату присваивания | ввести выражения с отбрасываемым значением и исключить этот случай из списка случаев, требующих преобразования |
| CWG 1343 | C++98 | последовательность вызовов деструкторов в инициализации агрегатов была недостаточно определена | полные выражения в инициализации агрегатов определены надлежащим образом |
| CWG 1383 | C++98 | список выражений, к которым применяется преобразование lvalue в rvalue для выражений с отбрасываемым значением, также охватывал перегруженные операторы | охватывать только операторы со встроенным значением |
| CWG 1576 | C++11 | преобразования lvalue в rvalue не применялись к выражениям volatile xvalue с отбрасываемым значением | применять преобразование в этом случае |
| CWG 2249 | C++98 | идентификаторы, которые должны были быть объявлены в деклараторах, не были выражениями id | они являются таковыми |
| CWG 2431 | C++11 | вызовы деструкторов временных объектов, которые связаны с ссылками, не были полными выражениями | они таковыми являются |
См. также
| C документация по Выражениям |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/language/expressions