Пространства имён
Варианты
Действия

Другие операторы

Материал из cppreference.com
< cpp‎ | language
 
 
Язык С++
Общие темы
Управление потоком
Операторы условного выполнения
Операторы итерации (циклы)
Операторы перехода
Функции
Объявление функции
Выражение лямбда-функции
Спецификатор inline
Спецификации динамических исключений(до C++17*)
Спецификатор noexcept(C++11)
Исключения
Пространства имён
Типы
Спецификаторы
decltype(C++11)
auto(C++11)
alignas(C++11)
Спецификаторы длительности хранения
Инициализация
Выражения
Альтернативные представления
Литералы
Логические - Целочисленные - С плавающей запятой
Символьные - Строковые - nullptr(C++11)
Определяемые пользователем(C++11)
Утилиты
Атрибуты(C++11)
Types
Объявление typedef
Объявление псевдонима типа(C++11)
Casts
Неявные преобразования - Явные преобразования
static_cast - dynamic_cast
const_cast - reinterpret_cast
Выделение памяти
Классы
Свойства функции класса
Специальные функции-элементы
Шаблоны
Разное
 
Выражения
Общие
Категории значений (lvalue, rvalue, xvalue)
Порядок оценки (точки последовательности)
Константные выражения
Потенциально оцениваемые выражения
Первичные выражения
Лямбда-выражения(C++11)
Литералы
Целочисленные литералы
Литералы с плавающей запятой
Логические литералы
Символьные литералы, включая управляющие последовательности
Строковые литералы
Литерал нулевого указателя(C++11)
Пользовательский литерал(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||b, a&&b, !a
a==b, a!=b, a<b, a>b, a<=b, a>=b, a<=>b(начиная с C++20)
a[b], *a, &a, a->b, a.b, a->*b, a.*b
a(...), a,b, a?b:c
выражение new
выражение delete
выражение throw
alignof
sizeof
sizeof...(C++11)
typeid
noexcept(C++11)
Выражения свёртки(C++17)
Альтернативные представления операторов
Приоритет и ассоциативность
Перегрузка операторов
Сравнение по умолчанию(C++20)
Преобразования
Неявные преобразования
Обычные арифметические преобразования
const_cast
static_cast
reinterpret_cast
dynamic_cast
Явные преобразования: (T)a, T(a), auto(a), auto{a}(начиная с C++23)
Пользовательское преобразование
 
Имя
оператора
Синтаксис Пере​гружа​емый Примеры прототипов (для class T)
Определение внутри класса Определение вне класса
вызов функции a(a1, a2)Да R T::operator()(Арг1&a1, Арг2&a2, ... ...);Н/Д
запятая a, bДа T2& T::operator,(T2 &b);T2& operator,(const T &a, T2 &b);
условный оператор a ? b : c Нет Н/ДН/Д

Содержание

[править]Объяснение

Оператор вызов функции обеспечивает семантику функции для любого объекта.

Условный оператор (математически формально именуемый тернарной условной операцией) проверяет логическое значение первого выражения и, в зависимости от полученного значения, оценивает и возвращает либо второе, либо третье выражение.

[править]Встроенный оператор вызова функции

Выражения вызова функции имеют вид

функция (арг1,арг2,арг3,...)

где

  • функция это тип выражения функции или тип указателя на функцию, а
  • арг1,арг2,арг3,... возможно, пустой список произвольных выражений или списки инициализации в фигурных скобках(начиная с C++11), за исключением того, что оператор запятая не разрешён на верхнем уровне, чтобы избежать двусмысленности.

Для вызова функции, не являющейся элементом, или статической функции-элемента, функция может быть lvalue, которое ссылается на функцию (в этом случае нет названия раздела подавляется), или значение prvalue типа указателя на функцию.

Имя функции (или элемента), указанное в функция может быть перегружено, используются правила разрешения перегрузки для определения того, какая перегрузка должна быть вызвана.

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

Чтобы вызвать функцию,

Выражение функция, а также все выражения arg1, arg2, arg3 и.д., предоставленные в качестве аргументов, оцениваются в произвольном порядке, непоследовательно по отношению друг к другу.

(до C++17)

Выражение функция упорядочивается перед каждым из выражений arg1, arg2, arg3 а также перед {rlp

(начиная с C++17)
, если таковые имеются. Выражения аргументов вычисляются в произвольном порядке, неопределённо упорядоченные по отношению друг к другу.

}} Каждый параметр функции инициализируется соответствующим аргументом после неявного преобразования, если это необходимо. Если соответствующего аргумента нет, используется соответствующий аргумент по умолчанию, а если его нет, программа не корректна. Если выполняется вызов функции-элемента, тогда указатель this на текущий объект преобразуется, как явное приведение к указателю this, ожидаемому функцией. Инициализация и уничтожение каждого параметра происходит в контексте вызывающей стороны, что означает, например, что если конструктор параметра выдаёт исключение, обработчики исключений, определённые в функции, даже как блок try функции, не рассматриваются. Если функция является вариативной функцией, продвижение аргументов по умолчанию применяются ко всем аргументам, соответствующим параметру многоточие. Заканчивается ли время жизни параметра, когда функция, в которой он определён, завершается, или в конце включающего полного выражения, определяется реализацией.

Тип возвращаемого значения выражения вызова функции это тип возвращаемого значения выбранной функции, определённый с использованием статической привязки (игнорируя ключевое слово virtual), даже если фактически вызванная перегруженная функция возвращает другой тип. Это позволяет перегруженным функциям возвращать указатели или ссылки на классы, которые являются производными от типа возвращаемого значения, возвращаемого базовой функцией, т.е. C++ поддерживает ковариантные возвращаемые типы. Если функция указывает деструктор, возвращаемый тип void.

Когда объект типа класса X передаётся или возвращается из функции, если все конструкторы копирования, конструкторы перемещения и деструкторы X либо тривиальны, либо удалены, и X имеет по крайней мере один не удалённый конструктор копирования или перемещения, реализациям разрешено создавать временный объект для хранения параметра функции или объекта результата.

Временный объект создаётся из аргумента функции или возвращаемого значения, соответственно, и параметр функции или возвращаемый объект инициализируется, как если бы с использованием неудалённого тривиального конструктора для копирования временного объекта (даже если этот конструктор недоступен или не будет выбран по разрешению перегрузки для выполнения копирования или перемещения объекта).

Это позволяет передавать или возвращать объекты небольших типов классов, такие как std::complex или std::span из функций в регистрах.

(начиная с C++17)

Категория значения выражения вызова функции это lvalue, если функция возвращает ссылку lvalue или ссылку rvalue на функцию, или xvalue, если функция возвращает ссылку rvalue на объект, и в противном случае это prvalue. Если выражение вызова функции является prvalue объектного типа, оно должно иметь полный тип, кроме , когда prvalue не материализовано, например(начиная с C++17) при использовании в качестве операнда decltype (или как правый операнд встроенного выражения оператора запятая, который является операндом decltype).

Выражение вызова функции похоже по синтаксису на инициализацию значения T(), на выражение приведения в стиле функцииT(A1) и на прямую инициализацию временного объекта T(A1, A2, A3, ...), где T имя типа.

#include <cstdio>struct S {int f1(double d){return printf("%f \n", d);// вызов функции с переменным аргументом}int f2(){return f1(7);// вызов функции-элемента, тоже самое, что и this->f1()// целочисленный аргумент преобразован в double}};void f(){ puts("функция вызвана");// вызов функции}int main(){ f();// вызов функции S s; s.f2();// вызов функции-элемента}

Вывод:

функция вызвана 7.000000

[править]Встроенный оператор запятая

Выражения оператора запятая имеют вид

E1,E2

В выражении с запятой E1, E2 вычисляется выражение E1, его результат отбрасывается (хотя, если оно имеет тип класса, оно не будет уничтожено до конца содержащего его полного выражения), и его побочные эффекты завершатся до начала оценки выражения E2(обратите внимание, что определяемый пользователем operator, не может гарантировать последовательность)(до C++17).

Тип, значение и категория значения результата выражения запятая являются в точности типом, значением и категорией значения второго операнда E2. Если E2 является временным выражением(начиная с C++17), результат выражения будет временным выражением(начиная с C++17). Если E2 является битовым полем, результатом будет битовое поле.

Запятая в различных списках, разделённых запятыми, таких как списки аргументов функций (f(a, b, c)) и списки инициализаторов int a[]={1,2,3}, не является оператором запятой. Если в таких контекстах необходимо использовать оператор запятая, его следует заключить в круглые скобки: f(a, (n++, n+b), c)

Использование выражения запятая без скобок в качестве второго (правого) аргумента оператора индексации не рекомендуется.

Например, a[b, c] не рекомендуется, а a[(b, c)] можно использовать.

(начиная с C++20)
(до C++23)

Выражение с запятой без скобок не может быть вторым (правым) аргументом оператора индексации. Например, a[b, c] неверно сформировано или эквивалентно a.operator[](b, c).

Для использования выражения запятая в качестве индекса необходимы скобки, например, a[(b, c)].

(начиная с C++23)
#include <iostream>int main(){// запятая часто используется для выполнения более чем одного// выражения, если грамматика языка допускает только одно выражение:   // * в третьем компоненте цикла forfor(int i =0, j =10; i <= j;++i, --j)// ^разделитель списка ^оператор запятаяstd::cout<<"i = "<< i <<" j = "<< j <<'\n';   // * в операторе return// return log("ошибка!"), -1;   // * в выражении инициализатора// MyClass( const Arg& arg)// : member{ throws_if_bad(arg), arg }   // и т.д.   // операторы-запятая могут быть объединены в цепочку; результат последнего// (самого правого) выражения является результатом всей цепочки:int n =1;int m =(++n, std::cout<<"n = "<< n <<'\n', ++n, 2*n);// m сейчас 6std::cout<<"m = "<<(++m, m)<<'\n';}

Вывод:

i = 0 j = 10 i = 1 j = 9 i = 2 j = 8 i = 3 j = 7 i = 4 j = 6 i = 5 j = 5 n = 2 m = 7

[править]Условный оператор

Выражения условных операторов имеют вид

E1?E2:E3

Первый операнд условного оператора оценивается и контекстно преобразуется в bool. После завершения оценки значения и всех побочных эффектов первого операнда, если результат был true, оценивается второй операнд. Если результат был false, оценивается третий операнд.

Тип и категория значения условного выражения E1 ? E2 : E3 определяются в соответствии со следующими правилами:

1) Если E2 или E3 имеет тип void, то должно выполняться одно из следующих условий, или программа не корректна:
1.1) Либо E2, либо E3 (но не оба сразу) является (возможно, заключенным в скобки) выражением throw. Результат условного оператора имеет тип и категорию значения другого выражения. Если другое выражение это битовое поле, результатом будет битовое поле. Такой условный оператор обычно использовался в C++11 constexpr программировании до C++14.
std::string str =2+2==4?"ok":throwstd::logic_error("2+2 != 4");
1.2) И E2, и E3 являются типом void (включая случай, когда они оба являются выражениями throw). Результатом является prvalue типа void.
2+2==4?throw123:throw456;
2) Иначе, если E2 или E3 являются битовыми полями glvalue той же категории значений и типов cv1 T и cv2 T, соответственно, операнды считаются имеющими тип cv T для остальной части этого раздела, где cv это объединение cv1 и cv2.
(начиная с C++14)
3) Иначе, если E2 и E3 имеют разные типы, по крайней мере один из которых является (возможно, cv-квалифицированным) типом класса, или оба являются значениями glvalue одной и той же категории значений и имеют один и тот же тип, за исключением cv-квалификации, тогда делается попытка сформировать последовательность неявного преобразования игнорируя доступ к элементу, является ли операнд битовым полем, или функция преобразования удалена от каждого из операндов до целевого типа, определённого другим операндом(начиная с C++11), как описано ниже. Операнд (назовём его X) типа TX может быть преобразован в целевой тип другого операнда (назовём его Y) типа TY следующим образом:
3.1) Если Y является lvalue, целевой тип это TY&, и ссылка должна напрямую связываться с lvalue;
3.2) Если Y является xvalue, целевой тип это TY&&, и ссылка должна быть привязана напрямую;
3.3) Если Y является prvalue, или если ни одна из вышеуказанных последовательностей преобразования не может быть сформирована и по крайней мере одно из TX и TY является (возможно, cv-квалифицированным) типом класса,
3.3.1) если TX и TY относятся к одному и тому же типу класса (игнорируя cv-квалификацию) и TY cv-квалифицирован, как TX, целевой тип это TY,
3.3.2) иначе, если TY является базовым классом TX, целевой тип это TY с cv-квалификаторами TX
struct A {};struct B : A {};using T =const B; A a =true? A(): T();// Y = A(), TY = A, X = T(), TX = const B. Целевой тип = const A
3.3.3) иначе, целевой тип это тип, чей Y будет после применения стандартных преобразований lvalue-в-rvalue, массива в указатель и функции в указатель
3.4) Если обе последовательности могут быть сформированы (E2 для целевого типа E3 и E3 для целевого типа E2), или может быть сформирована только одна, то это неоднозначная последовательность преобразования, программа некорректна.
3.5) Если может быть сформирована ровно одна последовательность преобразования (обратите внимание, что она всё ещё может быть неправильно сформирована, например, из-за нарушения доступа), эта последовательность преобразования применяется, и преобразованный операнд используется вместо исходного операнда для оставшейся части этого описания (начиная с (4))
3.6) Если последовательность преобразования не может быть сформирована, операнды остаются неизменными до конца этого описания
4) Если E2 и E3 являются glvalue одного типа и одной и той же категории значений, то результат имеет тот же тип и категорию значений и является битовым полем, если хотя бы одно из E2 и E3 битовое поле.
5) Иначе, результатом будет prvalue. Если E2 и E3 не одного и того же типа, и любой из них имеет (возможно, cv-квалифицированный) тип класса, разрешение перегрузки выполняется с использованием встроенных кандидатов, указанных ниже, чтобы попытаться преобразовать операнды во встроенные типы. Если разрешение перегрузки не удаётся, программа некорректна. В противном случае применяются выбранные преобразования, а преобразованные операнды используются вместо исходных операндов для шага 6.
6) Преобразования lvalue в rvalue, массива в указатель и функции в указатель применяются ко второму и третьему операндам. Затем,
6.1) Если оба E2 и E3 теперь имеют один и тот же тип, результатом будет prvalue этого типа , обозначающее временный объект инициализированный(до C++17)объект результата которого инициализирован(начиная с C++17) копией из любого операнда, выбранного после оценки E1.
6.2) Если и E2, и E3 имеют арифметический или перечисляемый тип: применяются обычные арифметические преобразования для приведения их к общему типу, и этот тип является результатом.
6.3) Если и E2, и E3 являются указателями, или один является указателем, а другой константой нулевого указателя, то применяются преобразования указателей и квалификационные преобразования, чтобы привести их к общему типу, и этот тип и есть результат.
int*intPtr;// nullptr становится int* static_assert(std::is_same_v<decltype(true?nullptr:intPtr), int*>);
6.4) Если и E2, и E3 являются указателями на элементы, или один указатель на элемент, а другой константа нулевого указателя, то применяются преобразования указателя на элемент и квалификационные преобразования, чтобы привести их к общему типу, и этот тип является результатом.
struct A{int* m_ptr;} a;int* A::* memPtr =&A::m_ptr;// memPtr это указатель на элемент m_ptr в A static_assert(std::is_same_v<decltype(false?memPtr:nullptr), int*A::*>);// memPtr делает nullptr типом указателя на элемент m_ptr из A static_assert(std::is_same_v<decltype(false?a.*memPtr:nullptr), int*>);// a.*memPtr теперь просто указатель на int, и nullptr также становится// указателем на int
6.5) Если и E2, и E3 являются константами нулевого указателя и хотя бы одна из них имеет тип std::nullptr_t, то тип результата будет std::nullptr_t.
6.6) Во всех остальных случаях программа некорректна.

Для каждой пары продвинутых арифметических типов L и R и для каждого типа P, где P это указатель, указатель на элемент или тип перечисления с ограниченной областью видимости, следующие сигнатуры функций участвуют в разрешении перегрузки, выполняемом на шаге 5 приведенных выше правил:

LR operator?:(bool, L, R );
P operator?:(bool, P, P );

где LR это результат обычных арифметических преобразований, выполненных над L и R. Оператор “?:” не может быть перегружен, эти сигнатуры функций существуют только для разрешения перегрузки.

Возвращаемый тип условного оператора также доступен как свойство двоичного типа std::common_type.

#include <iostream>#include <string>struct Node { Node* next;int data;// конструктор копирования с глубоким копированием Node(const Node& other): next(other.next? new Node(*other.next):NULL) , data(other.data){} Node(int d): next(NULL), data(d){} ~Node(){ delete next ;}};int main(){// простой пример rvalueint n =1>2?10:11;// 1>2 ложь, поэтому n = 11// простой пример lvalueint m =10;(n == m ? n : m)=7;// n == m ложь, поэтому m = 7std::cout<<"n = "<< n <<"\nm = "<< m;//вывод результата}

Вывод:

n = 11 m = 7

[править]Стандартная библиотека

Многие классы стандартной библиотеки перегружают operator() для использования в качестве объектов функций.

удаляет объект или массив
(public функция-элемент std::default_delete)[править]
возвращает сумму двух аргументов
(public функция-элемент std::plus)[править]
возвращает разницу между двумя аргументами
(public функция-элемент std::minus)[править]
возвращает произведение двух аргументов
(public функция-элемент std::multiplies)[править]
возвращает результат деления первого аргумента на второй аргумент
(public функция-элемент std::divides)[править]
возвращает остаток от деления первого аргумента на второй аргумент
(public функция-элемент std::modulus)[править]
возвращает отрицание аргумента
(public функция-элемент std::negate)[править]
проверяет, равны ли аргументы
(public функция-элемент std::equal_to)[править]
проверяет аргументы на неравенство
(public функция-элемент std::not_equal_to)[править]
проверяет, больше ли первый аргумент второго
(public функция-элемент std::greater)[править]
проверяет, меньше ли первый аргумент второго
(public функция-элемент std::less)[править]
проверяет, больше ли первый аргумент второго или равен ему
(public функция-элемент std::greater_equal)[править]
проверяет, меньше ли первый аргумент второго или равен ему
(public функция-элемент std::less_equal)[править]
возвращает логическое И двух аргументов
(public функция-элемент std::logical_and)[править]
возвращает логическое ИЛИ двух аргументов
(public функция-элемент std::logical_or)[править]
возвращает логическое НЕ аргумента
(public функция-элемент std::logical_not)[править]
возвращает результат поразрядного И двух аргументов
(public функция-элемент std::bit_and)[править]
возвращает результат поразрядного ИЛИ двух аргументов
(public функция-элемент std::bit_or)[править]
возвращает результат побитового XOR двух аргументов
(public функция-элемент std::bit_xor)[править]
возвращает логическое дополнение результата вызова сохранённого предиката
(public функция-элемент std::unary_negate)[править]
возвращает логическое дополнение результата вызова сохранённого предиката
(public функция-элемент std::binary_negate)[править]
вызывает сохранённую функцию
(public функция-элемент std::reference_wrapper)[править]
вызывает цель
(public функция-элемент std::function<R(Args...)>)[править]
лексикографически сравнивает две строки, используя фасет сопоставления этой локали
(public функция-элемент std::locale)[править]
сравнивает два значения типа value_type
(public функция-элемент std::map::value_compare)[править]
сравнивает два значения типа value_type
(public функция-элемент std::multimap::value_compare)[править]
выполняет функцию
(public функция-элемент std::packaged_task)[править]
(C++11)
продвигает состояние движка и возвращает сгенерированное значение
(public функция-элемент std::linear_congruential_engine)[править]
(C++11)
генерирует следующее случайное число в распределении
(public функция-элемент std::uniform_int_distribution)[править]

Оператор запятая не перегружен ни одним классом стандартной библиотеки. Библиотека boost использует operator, в boost.assign, boost.spirit и других библиотеках. Библиотека доступа к базе данных SOCI также перегружает operator,.

[править]Отчёты о дефектах

Следующие изменения поведения были применены с обратной силой к ранее опубликованным стандартам C++:

Номер Применён Поведение в стандарте Корректное поведение
CWG 446 C++98 не было указано, создаётся ли временный объект для
преобразования lvalue-в-rvalue в условном операторе
всегда создаёт временный объект, если
оператор возвращает класс rvalue
CWG 462 C++98 если второй операнд выражения с запятой является временным,
не указано, будет ли продлено его время жизни,
когда результат выражения с запятой будет привязан к ссылке
результат выражения запятой в этом
случае является временным (следовательно,
его время жизни продлевается)
CWG 587 C++98 когда второй и третий операнды условного выражения являются
значениями lvalue одного и того же типа, за исключением
cv-квалификации, результатом было значение lvalue, если эти
операнды имеют классовые типы, или значение rvalue
в противном случае
в этом случае результатом всегда
является lvalue
CWG 1029 C++98 тип вызова деструктора не был специфицирован специфицирован как void
CWG 1550 C++98 выражение throw в скобках не разрешалось в условных
выражениях, если другой операнд не являлся void
разрешено
CWG 1560 C++98 void операнд в условных выражениях вызывал необоснованное
преобразование lvalue-в-rvalue для другого операнда, что
всегда приводило к rvalue
условное выражение с void может быть lvalue
CWG 1642 C++98 выражение функция в выражении вызова функции может быть
lvalue указателем на функцию
не допускается
CWG 1805 C++98 в случае 3.3.3) условных выражений преобразования массива
в указатель и функции в указатель не применялись
применяются преобразования
CWG 1895 C++14 неясно, предотвращает ли удалённая или недоступная функция
преобразования преобразование в условных выражениях,
а преобразования из базового класса в производный класс
prvalue не учитывались
обрабатывается как разрешение перегрузки
CWG 1932 C++14 битовые поля одного типа отсутствовали в условных выражениях обрабатывается базовыми типами
CWG 2226 C++11 при определении целевого типа другого операнда условного
оператора ссылка не может быть привязана к xvalue, если этот
операнд является lvalue
позволено
CWG 2321 C++98 при определении целевого типа другого операнда условного
оператора тип производного класса не мог быть преобразован в
тип базового класса с меньшей cv-квалификацией
разрешено преобразовывать в тип
базового класса с cv-квалификацией из
операнда производного класса

[править]Смотрите также

Приоритет операторовПерегрузка операторов

Общие операторы
присваиваниеинкремент
декремент
арифметическиелогическиесравнениядоступ к элементудругие

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)

Документация C по Другие операторы
close