Выражения
Выражение — это последовательность операторов и операндов, задающая вычисление.
Вычисление выражения может давать результат (например, вычисление 2 + 2 дает результат 4) и может приводить к побочным эффектам (например, вычисление std::printf("%d", 4) выводит символ '4' в стандартный поток вывода).
Каждое выражение C++ характеризуется двумя независимыми свойствами: типом и категорией значения.
Общие сведения
- категории значений (lvalue, rvalue, glvalue, prvalue, xvalue(начиная с C++11)) классифицируют выражения по их значениям
- порядок вычисления аргументов и подвыражений определяет последовательность получения промежуточных результатов
Операторы
| Основные операторы | ||||||
|---|---|---|---|---|---|---|
| Присваивание |
Инкремент, декремент | Арифметические | Логические | Сравнения |
Доступ к членам | Другие |
a = b a += b a -= b a *= b a /= b a %= b a &= b a |= b a ^= b a <<= b a >>= b | ++a --a a++ a-- | +a -a a + b a - b a * b a / b a % b ~a a & b a | b a ^ b a << b a >> b | !a a && b a || b | a == b a != b a < b a > b a <= b a >= b a <=> b | a[...] *a &a a->b a.b a->*b a.*b | вызов функцииa(...) |
запятаяa, b |
||||||
условный операторa ? b : c |
||||||
| Специальные операторы | ||||||
|
|
||||||
- приоритет операторов определяет порядок связывания операторов с их аргументами
- альтернативные представления — это альтернативные написания некоторых операторов
- перегрузка операторов позволяет задавать поведение операторов для определяемых пользователем классов.
Преобразования
- стандартные преобразования — неявные преобразования из одного типа в другой
const_castпреобразованиеstatic_castпреобразованиеdynamic_castпреобразованиеreinterpret_castпреобразование- явное приведение — преобразование с использованием записи приведения в стиле C и функциональной записи
- определяемое пользователем преобразование позволяет задавать преобразования из определяемых пользователем классов
Выделение памяти
- выражение new динамически выделяет память
- выражение delete динамически освобождает память
Прочее
- константные выражения могут вычисляться во время компиляции и использоваться в контексте времени компиляции (аргументы шаблонов, размеры массивов и т. д.)
sizeofalignoftypeid- выражение 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++26) |
Любое выражение в круглых скобках также классифицируется как первичное выражение: это гарантирует, что скобки имеют более высокий приоритет, чем любой оператор. Скобки сохраняют значение, тип и категорию значения.
Литералы
Литералы — это токены программы C++, представляющие константные значения, записанные в исходном коде.
- целочисленные литералы — это десятичные, восьмеричные, шестнадцатеричные или двоичные числа целочисленного типа.
- символьные литералы — это отдельные символы типа
- char или wchar_t
| (начиная с C++11) |
| (начиная с C++20) |
- литералы с плавающей точкой — это значения типа float, double или longdouble
- строковые литералы — это последовательности символов типа
- constchar[] или constwchar_t[]
| (начиная с C++11) |
| (начиная с C++20) |
-
логические литералы — это значения типа bool, то есть
trueиfalse
| (начиная с C++11) |
Полные выражения
Следующие выражения являются полными выражениями:
| (начиная с C++20) |
- деклараторы простых объявлений или инициализаторы членов, включая составляющие выражения инициализаторов
- вызовы деструкторов, выполняемые в конце времени жизни объектов, за исключением временных объектов, время жизни которых не было продлено
| (начиная с C++26) |
- выражения, которые не являются подвыражением какого-либо другого выражения и не входят иным образом ни в одно полное выражение
Если согласно определению языковой конструкции она приводит к неявному вызову функции, использование этой языковой конструкции для целей данного определения считается выражением. Преобразования результата выражения, выполняемые для удовлетворения требований языковой конструкции, в которой это выражение встречается, также считаются частью полного выражения.
Для инициализатора частью полного выражения также считается выполнение инициализации сущности (включая вычисление инициализаторов по умолчанию для членов агрегата)(начиная с C++14).
Подвыражение выражения E является непосредственным подвыражением E или подвыражением непосредственного подвыражения E. Обратите внимание, что выражения в «теле функции» лямбда-выражений не являются подвыражениями лямбда-выражения.(начиная с C++11)
Непосредственными подвыражениями выражения E являются
- составляющие выражения операндов
E,
| (начиная с C++14) |
| (начиная с C++11) |
- любой вызов функции, который
Eвыполняет неявно, или - если
Eявляется вызовом функции или неявно вызывает функцию, составляющие выражения каждого аргумента по умолчанию, используемого при вызове.
Составляющее выражение определяется следующим образом:
- Составляющим выражением выражения является само это выражение.
- Составляющими выражениями списка инициализации в фигурных скобках или списка выражений (возможно, заключенного в скобки) являются составляющие выражения элементов соответствующего списка.
- Составляющими выражениями инициализатора, начинающегося с
=, являются составляющие выражения инициализирующей конструкции.
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”)
Потенциально вычисляемые выражения
| Выражение является потенциально вычисляемым, если только | (до C++11) | ||||
| Следующие операнды являются невычисляемыми операндами — они не вычисляются:
Выражение является потенциально вычисляемым, если только
| (начиная с C++11) |
Потенциально вычисляемые выражения являются использованиями ODR.
Выражения с отбрасываемым значением
Выражение с отбрасываемым значением — это выражение, используемое только ради побочных эффектов. Вычисленное значение такого выражения отбрасывается. К таким выражениям относятся полное выражение любого операторного выражения, левый операнд встроенного оператора запятая или операнд выражения приведения, приводящего к типу void.
Преобразования массива в указатель и функции в указатель никогда не применяются к значению, вычисленному выражением с отбрасываемым значением. Преобразование lvalue в rvalue применяется тогда и только тогда, когда выражение является glvalue с квалификатором volatile и имеет одну из следующих форм (требуется встроенная семантика, допускаются круглые скобки):
- выражение-идентификатор,
| (начиная с C++26) |
- выражение индексирования массива,
- выражение доступа к члену класса,
- операция разыменования,
- операция с указателем на член,
- условное выражение, в котором и второй, и третий операнды являются одним из этих выражений,
- выражение с запятой, в котором правый операнд является одним из этих выражений.
Кроме того, если lvalue имеет тип класса с квалификатором volatile, для инициализации результирующего временного rvalue требуется конструктор копирования volatile.
| Если выражение является prvalue невойдового типа (после любого преобразования lvalue в rvalue, которое могло произойти), выполняется материализация временного объекта. Компиляторы могут выдавать предупреждения, если значение, объявленное | (начиная с 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 | идентификаторы, которые должны были быть объявлены в деклараторах, не считались выражениями-идентификаторами | считаются |
| CWG 2431 | C++11 | вызовы деструкторов временных объектов, привязанных к ссылкам, не считались полными выражениями | считаются |
См. также
| Документация по C для выражений |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/language/expressions