Expressions
Выражение — это последовательность операторов и их операндов , которая определяет вычисление.
Вычисление выражения может производить результат (например, вычисление 2 + 2 даёт результат 4 ) и может вызывать побочные эффекты (например, вычисление std:: printf ( "%d" , 4 ) выводит символ '4' на стандартный вывод).
Каждое выражение в C++ характеризуется двумя независимыми свойствами: типом и категорией значения.
Содержание |
Общее
- категории значений (lvalue, rvalue , glvalue, prvalue, xvalue (since C++11) ) классифицируют выражения по их значениям
- порядок вычисления аргументов и подвыражений определяет порядок получения промежуточных результатов
Операторы
| Общие операторы | ||||||
|---|---|---|---|---|---|---|
| присваивание |
инкремент
декремент |
арифметические | логические | сравнения |
доступа к членам
класса |
прочие |
|
a
=
b
|
++
a
|
+
a
|
!
a
|
a
==
b
|
a
[
...
]
|
вызов функции
a ( ... ) |
|
запятая
a, b |
||||||
|
условный оператор
a ? b : c |
||||||
| Специальные операторы | ||||||
|
static_cast
преобразует один тип в другой связанный тип
|
||||||
- приоритет операторов определяет порядок, в котором операторы связываются со своими аргументами
- альтернативные представления являются альтернативными написаниями для некоторых операторов
- перегрузка операторов позволяет задавать поведение операторов для пользовательских классов.
Преобразования
- стандартные преобразования неявные преобразования из одного типа в другой
-
const_castпреобразование -
static_castпреобразование -
dynamic_castпреобразование -
reinterpret_castпреобразование - явное приведение преобразование с использованием C-style нотации и function-style нотации
- пользовательское преобразование позволяет задать преобразование из пользовательских классов
Выделение памяти
- new expression динамически выделяет память
- delete expression динамически освобождает память
Другое
- constant expressions могут вычисляться на этапе компиляции и использоваться в контексте времени компиляции (аргументы шаблонов, размеры массивов и т.д.)
-
sizeof -
alignof -
typeid - throw-expression
Первичные выражения
Операндами любого оператора могут быть другие выражения или первичные выражения (например, в 1 + 2 * 3 операндами operator+ являются подвыражение 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) |
Полные выражения
Составное выражение определяется следующим образом:
- Составное выражение выражения — это само это выражение.
- Составные выражения списка инициализации в фигурных скобках или (возможно, заключенного в круглые скобки) списка выражений — это составные выражения элементов соответствующего списка.
-
Составные выражения
инициализатора
, который начинается с
=, являются составными выражениями initializer-clause .
int num1 = 0; num1 += 1; // Случай 1: составное выражение "num += 1" — это "num += 1" int arr2[2] = {2, 22} // Случай 2: составные выражения // "{2, 22}" — это "2" и "22" // Случай 3: составные выражения "= {2, 22}" // — это составные выражения "{2, 22}" // (т.е. также "2" и "22")
Непосредственные подвыражения выражения E это
- составные выражения E операндов,
|
(since C++14) |
|
(since C++11) |
- любой вызов функции, который E неявно вызывает, или
- если E является вызовом функции или неявно вызывает функцию, составные выражения каждого аргумента по умолчанию используемого в вызове.
Подвыражение выражения E является непосредственным подвыражением E или подвыражением непосредственного подвыражения E . Обратите внимание, что выражения, появляющиеся в «теле функции» лямбда-выражений, не являются подвыражениями лямбда-выражения. (начиная с C++11)
Следующие выражения являются полными выражениями :
| (начиная с C++20) |
- деклараторы простых объявлений или инициализаторов членов , включая составные выражения инициализаторов
- вызовы деструкторов , сгенерированные в конце времени жизни объектов, за исключением временных объектов, время жизни которых не было продлено
|
(начиная с C++26) |
- выражения, которые не являются подвыражением какого-либо другого выражения и не входят в состав какого-либо полного выражения
Если языковая конструкция определена как производящая неявный вызов функции, использование этой языковой конструкции считается выражением для целей данного определения. Преобразования, применяемые к результату выражения для удовлетворения требований языковой конструкции, в которой это выражение присутствует, также считаются частью полного выражения.
Для инициализатора выполнение инициализации сущности (включая вычисление инициализаторов по умолчанию для членов агрегата) (начиная с C++14) также считается частью полного выражения.
Потенциально вычисляемые выражения
|
Выражение является потенциально вычисляемым за исключением случаев, когда
|
(до C++11) | ||
|
Следующие операнды являются невычисляемыми операндами , они не вычисляются:
Выражение является потенциально вычисляемым за исключением случаев, когда
|
(начиная с C++11) |
Потенциально вычисляемые выражения являются ODR-использованием .
|
Этот раздел не завершён
Причина: пример невычисляемых операндов |
Выражения с отбрасываемым значением
Отбрасываемое выражение — это выражение, которое используется только для его побочных эффектов. Значение, вычисляемое таким выражением, отбрасывается. К таким выражениям относятся полное выражение любого выражения-оператора , левый операнд встроенного оператора запятая или операнд приведения типа, которое приводится к типу void .
Преобразования массива в указатель и функции в указатель никогда не применяются к значению, вычисляемому выражением отброшенного значения. Преобразование lvalue в rvalue применяется тогда и только тогда, когда выражение является volatile-квалифицированным glvalue и имеет одну из следующих форм (требуется встроенное значение, возможно в скобках):
- id-expression,
- array subscript expression,
- class member access expression,
- indirection,
- pointer-to-member operation,
- conditional expression where both the second and the third operands are one of these expressions,
- comma expression where the right operand is one of these expressions.
Кроме того, если lvalue имеет тип класса с квалификатором volatile, для инициализации результирующего временного объекта rvalue требуется конструктор копирования с квалификатором volatile.
|
Если выражение является prvalue не-void типа (после любого преобразования lvalue-to-rvalue, которое могло произойти), происходит материализация временного объекта .
Компиляторы могут выдавать предупреждения, когда выражение, отличное от приведения к
void
, отбрасывает значение, объявленное с
|
(начиная с C++17) |
Эквивалентность выраженийНесколько выражений e1 , e2 , ..., eN являются эквивалентными выражениями если выполняются все следующие условия:
e1 является эквивалентным выражению e2 тогда и только тогда, когда e1 и e2 являются эквивалентными выражениями (что означает e2 также является эквивалентным выражению e1 ). |
(начиная с C++20) |
Отчеты о дефектах
Следующие отчеты об изменениях в поведении, являющиеся дефектными, были применены ретроактивно к ранее опубликованным стандартам C++.
| DR | Применяется к | Поведение в опубликованной версии | Корректное поведение |
|---|---|---|---|
| CWG 1054 | C++98 |
присваивание значения volatile переменной может
приводить к избыточному чтению из-за преобразования lvalue-to-rvalue, применяемого к результату присваивания |
ввести discarded-value выражения
и исключить этот случай из списка случаев, требующих преобразование |
| CWG 1343 | C++98 |
порядок вызовов деструкторов при
агрегатной инициализации был недостаточно специфицирован |
full-expression в агрегатной инициализации
четко специфицированы |
| CWG 1383 | C++98 |
список выражений, где преобразование lvalue-to-rvalue
применяется к discarded-value выражениям, также включал перегруженные операторы |
охватывать только операторы
со встроенным значением |
| CWG 1576 | C++11 |
преобразования lvalue-to-rvalue не применялись
к discarded-value volatile xvalue выражениям |
применять преобразование
в этом случае |
| CWG 2249 | C++98 |
идентификаторы, объявляемые в деклараторах,
не являлись id-expression |
являются |
| CWG 2431 | C++11 |
вызовы деструкторов временных объектов,
которые связаны с ссылками, не являлись full-expression |
являются |
Смотрите также
|
Документация C
для
Выражения
|