Spec-Zone.ru › C++

Выражения

Выражение — это последовательность операторов и их операндов, которая задаёт вычисление.

Вычисление выражения может дать результат (например, вычисление 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
Специальные операторы

static_cast преобразует один тип в другой, родственный ему тип
dynamic_cast преобразует в рамках иерархии наследования
const_cast добавляет или удаляет cv-квалификаторы
reinterpret_cast преобразует тип в неродственный тип
Оператор преобразования в стиле C преобразует один тип в другой, используя смесь static_cast, const_cast, и reinterpret_cast
new создаёт объекты с динамическим сроком жизни
delete уничтожает объекты, ранее созданные оператором new, и освобождает полученную область памяти
sizeof запрашивает размер типа
sizeof... запрашивает размер пакета параметров (с C++11)
typeid запрашивает информацию о типе
noexcept проверяет, может ли выражение выбросить исключение (с C++11)
alignof запрашивает требования к выравниванию типа (с C++11)

  • приоритет операторов определяет порядок связывания операторов с их аргументами
  • альтернативные записи представляют собой альтернативные способы написания некоторых операторов
  • перегрузка операторов позволяет задать поведение операторов для пользовательских классов.

Преобразования

  • стандартные преобразования неявные преобразования из одного типа в другой
  • 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)
  • выражения requires
(с C++20)

Любое выражение в скобках также классифицируется как первичное выражение: это гарантирует, что скобки имеют более высокий приоритет, чем любой оператор. Скобки сохраняют значение, тип и категорию значения.

Литералы

Литералы — это токены программы C++, которые представляют собой константные значения, встраиваемые в исходный код.

  • целочисленные литералы — это десятичные, восьмеричные, шестнадцатеричные или двоичные числа целочисленного типа.
  • символьные литералы — это отдельные символы типа
    • char или wchar_t
  • char16_t или char32_t
(с C++11)
  • char8_t
(с C++20)
  • вещественные литералы — это значения типа float, double или long double
  • строковые литералы — это последовательности символов типа
    • const char[] или const wchar_t[]
  • const char16_t[] или const char32_t[]
(с C++11)
  • const char8_t[]
(с C++20)
  • булевы литералы — это значения типа bool, а именно true и false
END_OF_DOCUMENT_MARKER
  • nullptr — это литерал указателя, который задаёт значение нулевого указателя
  • пользовательские литералы — это константы пользовательского типа
(с 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
  • если E создаёт объект агрегированного типа, составные выражения для каждого инициализатора по умолчанию для члена, используемого в инициализации,
(с C++14)
  • если E является лямбда-выражением, инициализация сущностей, захваченных по значению, и составные выражения для инициализаторов захватов,
(с C++11)
  • любой вызов функции, который E неявно вызывает, или
  • если E является вызовом функции или неявно вызывает функцию, составные выражения для каждого аргумента по умолчанию, используемого в вызове.

Подвыражение выражения E — это непосредственное подвыражение E или подвыражение непосредственного подвыражения E. Обратите внимание, что выражения, присутствующие в «теле функции» лямбда-выражений, не являются подвыражениями лямбда-выражения.(с C++11)

Полное выражение — это

  • невычисляемый операнд,
  • выражение-константа,
  • немедленный вызов,
(с C++20)
  • декларатор простого объявления или инициализатора члена, включая составные выражения инициализатора,
  • вызов деструктора, сгенерированного в конце жизни объекта, отличного от временного объекта, чья жизнь не была продлена, или
  • выражение, которое не является подвыражением другого выражения и которое не является иначе частью полного выражения.

Если языковая конструкция определена таким образом, что она производит неявный вызов функции, то использование такой языковой конструкции считается выражением для целей данного определения. Преобразования, применяемые к результату выражения для удовлетворения требований языковой конструкции, в которой появляется выражение, также считаются частью полного выражения.

Для инициализатора выполнение инициализации сущности (включая вычисление инициализаторов членов по умолчанию агрегированного объекта)(с C++14) также считается частью полного выражения.

Выражения, потенциально подлежащие вычислению

Выражение потенциально вычисляется, за исключением случаев

  • если оно является операндом оператора sizeof, или
  • если оно является операндом оператора typeid и не обозначает lvalue типа полиморфного класса.
(до C++11)

Следующие операнды являются невычисляемыми, они не вычисляются:

  • выражения, к которым применяется оператор typeid, за исключением glvalue типов полиморфных классов
  • выражения, являющиеся операндами оператора sizeof
  • операнды оператора noexcept
  • операнды спецификатора decltype
  • constraint-expression определений концепций
  • выражения, следуемые за ключевым словом requires в requires-клаузах
  • выражения, появляющиеся в requirement-seq requires-выражений
(с C++20)

Выражение потенциально вычисляется, за исключением случаев

  • если оно является невычисляемым операндом, или
  • если оно является подвыражением невычисляемого операнда.
(с C++11)

Выражения со значениями, отбрасываемыми

Выражение со значением, отбрасываемым — это выражение, используемое только для побочных эффектов. Вычисленное из него значение отбрасывается. Такие выражения включают полное выражение любого выражения-оператора, левый операнд встроенного оператора запятой или операнд выражения-приведения, которое приводится к типу void.

Преобразования «массив в указатель» и «функция в указатель» никогда не применяются к значению, вычисленному выражением со значением, отбрасываемым. Преобразование lvalue в rvalue применяется тогда и только тогда, когда выражение является glvalue с квалификатором volatile и имеет один из следующих видов (требуется встроенный смысл, возможно, в скобках):

  • выражение-идентификатор,
  • выражение индексации массива,
  • выражение доступа к члену класса,
  • косвенное обращение,
  • операция указателя на член,
  • условное выражение, где второй и третий операнды являются одним из этих выражений,
  • выражение с запятой, где правый операнд является одним из этих выражений.

Кроме того, если lvalue имеет тип класса с квалификатором volatile, требуется конструктор копирования с квалификатором volatile для инициализации полученного временного rvalue.

Если выражение является не-void prvalue (после возможного преобразования lvalue в rvalue), происходит создание временного объекта.

Компиляторы могут выводить предупреждения, когда выражение, отличное от приведения к void, отбрасывает объявленное значение [[nodiscard]].

(с C++17)

Эквивалентность выражений

Несколько выражений e1, e2, ..., eN являются эквивалентными по выражениям, если

  1. они имеют одинаковые эффекты;
  2. либо все они являются константными подвыражениями, либо ни одно из них не является;
  3. либо все они являются noexcept, либо ни одно из них не является.

e1 эквивалентно по выражениям e2 тогда и только тогда, когда e1 и e2 эквивалентны по выражениям (что означает, что e2 также эквивалентно e1).

(с 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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API