Operators

Arithmetic Operators

OperatorFunction
+ (unary)Unary plus
- (unary)Unary minus
* (binary)Multiplication
/Division
%Modulo
+ (binary)Addition
- (binary)Subtraction
Unary and binary operators

A unary operator (also called a monadic operator) is an operator with only one operand, while a binary operator (also called a dyadic operator) has two operands. For example, the plus sign in 1 + 2 is a binary operator, with 1 and 2 as its two operands. In addition, C++ has exactly one ternary operator, ?:.

Among arithmetic operators, there are two unary operators (unary plus and unary minus) and five binary operators (multiplication, division, modulo, addition, and subtraction). Unary operators have the highest precedence.

The modulo operator % means calculating the remainder obtained by dividing two integers, that is, finding the remainder.

When - is a binary operator, it performs subtraction, as in 2-1; when it is a unary operator, it performs negation, as in -1.

It is used as follows:

op=x-y*z

its value computed by op follows the usual mathematical precedence of addition, subtraction, multiplication, and division: operations with higher precedence are performed first; operations with equal precedence are performed according to associativity; and parentheses increase precedence.

Type Conversion in Arithmetic Operations

For binary arithmetic operators, when the types of the two variables involved in an operation are the same, no type conversion occurs, and the outcome is stored using the type of the participating variables. Otherwise, type conversion occurs so that the types of the two variables become consistent. See type conversion for the conversion rules.

For example, consider an integer (int) variable xx and another variable yy of type double-precision floating point (double):

  • Evaluating x/3 is an integer;
  • Evaluating x/3.0 is a double-precision floating-point value;
  • Evaluating x/y is a double-precision floating-point value;
  • Evaluating x*1/3 is an integer;
  • Evaluating x*1.0/3 is a double-precision floating-point value;

Bitwise Operators

See also: Bitwise Operations.

OperatorFunction
~Bitwise NOT
& (binary)Bitwise AND
``
^Bitwise XOR
<<Bitwise left shift
>>Bitwise right shift

For the meaning of bitwise operations, see the Bitwise Operations page. Note that bitwise operations have lower precedence than arithmetic operators (except for bitwise NOT), while bitwise AND, bitwise OR, and XOR have lower precedence than comparison operators (see the complete C++ operator precedence table). Therefore, take extra care when using them and add parentheses when necessary.

The behavior of a shift operation is undefined in the following cases:

  1. The right operand (that is, the number of positions to shift) is negative;
  2. The right operand is greater than or equal to the number of bits in the left operand;

For example, for a variable a of type int32_t, both a<<-1 and a<<32 are undefined.

For a left-shift operation on a signed nonnegative number, you must ensure that the shifted result can be represented by the original type; otherwise, the behavior is also undefined.1 Performing a left shift on a negative number is also undefined.2

For a right-shift operation, excess bits on the right are discarded, while the behavior on the left is more complicated: for unsigned numbers, 00 is added on the left3; for signed numbers, the most significant bit (which is the sign bit: 00 for nonnegative numbers and 11 for negative numbers) is replicated to fill the left side4.

Increment/Decrement Operators

Sometimes we need to increase a variable by 1 (increment) or decrease it by 1 (decrement). This is where the increment operator ++ and decrement operator -- come in handy.

Increment/decrement operators can be placed before or after a variable. They are called prefixes when placed before a variable and suffixes when placed after it. When used alone, prefixes and suffixes need no special distinction; if its value from that expression is used, however, attention is required. See the examples below for details. For more information, see the examples section of the introduction to references.

i = 100;

op1 = i++;  // op1 = 100, first op1 = i, then i = i + 1

i = 100;

op2 = ++i;  // op2 = 101, first i = i + 1, then assign op2

i = 100;

op3 = i--;  // op3 = 100, first assign op3, then i = i - 1

i = 100;

op4 = --i;  // op4 = 99, first i = i - 1, then assign op4

Compound Assignment Operators

Compound assignment operators are actually abbreviated forms of expressions. They can be divided into compound arithmetic operators +=, -=, *=, /=, %= and compound bitwise operators &=, |=, ^=, <<=, >>=.

For example, op = op + 2 can be written as op += 2, op = op - 2 can be written as op -= 2, and op= op * 2 can be written as op *= 2.

Conditional Operator

The conditional operator can be regarded as an abbreviation for an if statement. In a ? b : c, if expression a is true, the outcome of the conditional expression is b; otherwise, the outcome is c.

Comparison Operators

OperatorFunction
>Greater than
>=Greater than or equal to
<Less than
<=Less than or equal to
==Equal to
!=Not equal to

In particular, note that the equality operator == must be distinguished from the assignment operator =. This is especially important in conditional statements.

if (op=1) and if (op==1) look similar, but their actual functions differ greatly. The first statement assigns a value to op; if the assigned value is nonzero, it is true, so that condition of that expression is always satisfied and cannot serve as a test. The second statement is the one that tests its value from op.

Logical Operators

OperatorFunction
&&Logical AND
`
!Logical NOT
Result = op1 && op2;  // Result is true when both op1 and op2 are true

Result = op1 || op2;  // Result is true when either op1 or op2 is true

Result = !op1;  // Result is true when op1 is false

The built-in operators && and || perform short-circuit evaluation (if the outcome is already known after evaluating the first operand, the second operand is not evaluated). Overloaded operators do not have this property and always evaluate both operands.

Comma Operator

The comma operator separates multiple expressions. The separated expressions are evaluated in order from left to right, and its value from the entire expression is its value from the last expression. The comma expression has the lowest precedence of all operators.

exp1, exp2, exp3;  // The final value is the outcome of evaluating exp3.

Result = 1 + 2, 3 + 4, 5 + 6;
// Result is 3 rather than 11, because the assignment operator "=" has higher precedence
// than the comma operator, so assignment is performed before the comma operations.

Result = (1 + 2, 3 + 4, 5 + 6);

// To make its value from Result be the outcome of the comma operation, the entire expression
// should be enclosed in parentheses to increase its precedence. Only then is its value from Result 11.

Member Access Operators

OperatorFunction
[]Array subscript
.Object member
& (unary)Take address / obtain reference
* (unary)Indirection / dereference
->Pointer member

These operators are used to access members or memory of an object. Except for the last operator, all of the operators above can be overloaded. For material related to &, *, and ->, read the Pointers and References tutorials. Two rarely used operators, .* and ->*, are omitted here; for their specific usage, see the C++ language reference.

auto result1 = v[1];  // Get the object whose subscript in v is 2
auto result2 = p.q;   // Get member q of object p
auto result3 = p -> q;  // Get member q of the object pointed to by p, equivalent to (*p).q
auto result4 = &v;      // Get the pointer to v
auto result5 = *v;      // Get the object pointed to by pointer v

Complete C++ Operator Precedence Table

From C++ operator precedence - cppreference, with modifications.

OperatorDescriptionExampleOverloadable
Level 1
::Scope resolution operatorClass::age = 2;Not overloadable
Level 2
++Postfix increment operatorfor (int i = 0; i < 10; i++) cout << i;Overloadable
--Postfix decrement operatorfor (int i = 10; i > 0; i--) cout << i;Overloadable
type() type{}Explicit type conversionunsigned int a = unsigned(3.14);Overloadable
()Function callisdigit('1')Overloadable
[]Array element accessarray[4] = 2;Overloadable
.Object member accessobj.age = 34;Not overloadable
->Pointer member accessptr->age = 34;Overloadable
Level 3 (right-to-left associativity)
++Prefix increment operatorfor (i = 0; i < 10; ++i) cout << i;Overloadable
--Prefix decrement operatorfor (i = 10; i > 0; --i) cout << i;Overloadable
+Unary plusint i = +1;Overloadable
-Unary minusint i = -1;Overloadable
!Logical NOTif (!done) …Overloadable
~Bitwise NOTflags = ~flags;Overloadable
(type)C-style explicit type conversionint i = (int) floatNum;Overloadable
*Pointer dereferenceint data = *intPtr;Overloadable
&Address-ofint *intPtr = &data;Overloadable
sizeofReturn type sizeint size = sizeof floatNum; int size = sizeof(float);Not overloadable
newDynamic object allocationlong *pVar = new long; MyClass *ptr = new MyClass(args);Overloadable
new []Dynamic array allocationlong *array = new long[n];Overloadable
deleteDynamic object destructiondelete pVar;Overloadable
delete []Dynamic array destructiondelete [] array;Overloadable
Level 4
.*Class-object member pointerobj.*var = 24;Not overloadable
->*Class-pointer member pointerptr->*var = 24;Overloadable
Level 5
*Multiplicationint i = 2 * 4;Overloadable
/Divisionfloat f = 10.0 / 3.0;Overloadable
%Moduloint rem = 4 % 3;Overloadable
Level 6
+Additionint i = 2 + 3;Overloadable
-Subtractionint i = 5 - 1;Overloadable
Level 7
<<Bitwise left shiftint flags = 33 << 1;Overloadable
>>Bitwise right shiftint flags = 33 >> 1;Overloadable
Level 8
<=>Three-way comparison operatorif ((i <=> 42) < 0) ...Overloadable
Level 9
<Less thanif (i < 42) ...Overloadable
<=Less than or equal toif (i <= 42) ...Overloadable
>Greater thanif (i > 42) ...Overloadable
>=Greater than or equal toif (i >= 42) ...Overloadable
Level 10
==Equal toif (i == 42) ...Overloadable
!=Not equal toif (i != 42) ...Overloadable
Level 11
&Bitwise ANDflags = flags & 42;Overloadable
Level 12
^Bitwise XORflags = flags ^ 42;Overloadable
Level 13
``Bitwise OR`flags = flags
Level 14
&&Logical ANDif (conditionA && conditionB) ...Overloadable
Level 15
``Logical OR
Level 16 (right-to-left associativity)
? :Conditional operatorint i = a > b ? a : b;Not overloadable
throwThrow expressionthrow EClass("Message");Not overloadable
=Assignmentint a = b;Overloadable
+=Add and assigna += 3;Overloadable
-=Subtract and assignb -= 4;Overloadable
*=Multiply and assigna *= 5;Overloadable
/=Divide and assigna /= 2;Overloadable
%=Modulo and assigna %= 3;Overloadable
<<=Bitwise left-shift assignmentflags <<= 2;Overloadable
>>=Bitwise right-shift assignmentflags >>= 2;Overloadable
&=Bitwise AND assignmentflags &= new_flags;Overloadable
^=Bitwise XOR assignmentflags ^= new_flags;Overloadable
`=`Bitwise OR assignment`flags
Level 17
,Comma separatorfor (i = 0, j = 0; i < 10; i++, j++) ...Overloadable

Note that the table does not list operators such as const_cast, static_cast, dynamic_cast, reinterpret_cast, typeid, sizeof..., noexcept, and alignof, because their syntax is the same as a function call and cannot be ambiguous.

References and notes

Footnotes

  1. Before C++20, if the original value had a signed type and the shifted result could be represented by the unsigned version of the original type, the outcome was converted to the corresponding signed value; otherwise, the behavior was undefined. For left shifts of unsigned numbers, bits shifted out of the outcome type were discarded. Starting with C++20, a << b is specified as its value from a⋅2ba\cdot 2^b modulo 2N2^N (NN is the bit width of the outcome type), meaning that for both signed and unsigned numbers, a left shift directly discards bits shifted out of the outcome type (that is, arithmetic left shift / logical left shift). ↩

  2. Before C++20. See 1 for behavior starting with C++20. ↩

  3. That is, logical right shift. ↩

  4. That is, arithmetic right shift. Before C++20, right shifting a signed number was implementation-defined; most implementations used arithmetic right shift. Starting with C++20, a >> b is specified as ⌊a/2b⌋\lfloor a/2^b\rfloor, so right-shifting a signed number is an arithmetic right shift. ↩

This content comes from OI Wiki: Operators. See the original for authors and revision history. AIOJ has adapted the formatting, in-site links, and resource paths.

Content is shared under CC BY-SA 4.0 and SATA license; additional terms are governed by the original notice. Thanks to the OI Wiki authors and contributors; per the SATA terms, please visit the OI Wiki repository and star it to show your support.