Difference between revisions of "cpp/language/operator incdec"
(→Built-in prefix operators: ++bool is gone) |
m (→Built-in prefix operators: fix: i => u.) |
||
(16 intermediate revisions by 10 users not shown) | |||
Line 1: | Line 1: | ||
{{title|Increment/decrement operators}} | {{title|Increment/decrement operators}} | ||
{{cpp/language/expressions/navbar}} | {{cpp/language/expressions/navbar}} | ||
− | Increment/decrement operators | + | Increment/decrement operators increment or decrement the value of the object. |
− | {| class="wikitable" style="font-size:85%;" | + | {|class="wikitable" style="font-size:85%;" |
|- | |- | ||
− | ! rowspan="2" | Operator name | + | !rowspan="2"|Operator name |
− | ! rowspan="2" | Syntax | + | !rowspan="2"|Syntax |
− | ! rowspan="2" | {{rlp|operators|Over​load​able}} | + | !rowspan="2"|{{rlp|operators|Over​load​able}} |
− | ! colspan="2" | Prototype examples (for {{c|class T}}) | + | !colspan="2"|Prototype examples (for {{c/core|class T}}) |
|- | |- | ||
− | ! Inside class definition | + | !Inside class definition |
− | ! Outside class definition | + | !Outside class definition |
|- | |- | ||
− | | pre-increment | + | |pre-increment |
− | | {{tt|++a}} | + | |{{tt|++a}} |
− | | {{yes}} | + | |{{yes}} |
− | | {{c|T& T::operator++();}} | + | |{{c|T& T::operator++();}} |
− | | {{c|T& operator++(T& a);}} | + | |{{c|T& operator++(T& a);}} |
|- | |- | ||
− | | pre-decrement | + | |pre-decrement |
− | | {{tt|--a}} | + | |{{tt|--a}} |
− | | {{yes}} | + | |{{yes}} |
− | | {{c|T& T::operator--();}} | + | |{{c|T& T::operator--();}} |
− | | {{c|T& operator--(T& a);}} | + | |{{c|T& operator--(T& a);}} |
|- | |- | ||
− | | post-increment | + | |post-increment |
− | | {{tt|a++}} | + | |{{tt|a++}} |
− | | {{yes}} | + | |{{yes}} |
− | | {{c|T T::operator++(int);}} | + | |{{c|T T::operator++(int);}} |
− | | {{c|T operator++(T& a, int);}} | + | |{{c|T operator++(T& a, int);}} |
|- | |- | ||
− | | post-decrement | + | |post-decrement |
− | | {{tt|a--}} | + | |{{tt|a--}} |
− | | {{yes}} | + | |{{yes}} |
− | | {{c|T T::operator--(int);}} | + | |{{c|T T::operator--(int);}} |
− | | {{c|T operator--(T& a, int);}} | + | |{{c|T operator--(T& a, int);}} |
|- | |- | ||
− | | colspan="5" | | + | |colspan="5"| |
:'''Notes'''<br> | :'''Notes'''<br> | ||
− | * Prefix versions of the built-in operators return ''references'' and postfix versions return ''values'', and typical {{rlp|operators|user-defined overloads}} follow the pattern so that the user-defined operators can be used in the same manner as the built-ins. However, in a user-defined operator overload, any type can be used as return type (including {{c|void}}). | + | * Prefix versions of the built-in operators return ''references'' and postfix versions return ''values'', and typical {{rlp|operators|user-defined overloads}} follow the pattern so that the user-defined operators can be used in the same manner as the built-ins. However, in a user-defined operator overload, any type can be used as return type (including {{c/core|void}}). |
− | * The {{c|int}} parameter is a dummy parameter used to differentiate between prefix and postfix versions of the operators. When the user-defined postfix operator is called, the value passed in that parameter is always zero, although it may be changed by calling the operator using function call notation (e.g., {{c|a.operator++(2)}} or {{c|operator++(a, 2)}}). | + | * The {{c/core|int}} parameter is a dummy parameter used to differentiate between prefix and postfix versions of the operators. When the user-defined postfix operator is called, the value passed in that parameter is always zero, although it may be changed by calling the operator using function call notation (e.g., {{c|a.operator++(2)}} or {{c|operator++(a, 2)}}). |
|} | |} | ||
− | === | + | ===Prefix operators=== |
− | + | The prefix increment and decrement expressions have the form | |
− | + | {{sdsc begin}} | |
− | + | {{sdsc|{{ttb|++}} {{spar|expression}}}} | |
+ | {{sdsc|{{ttb|--}} {{spar|expression}}}} | ||
+ | {{sdsc end}} | ||
+ | @1@ prefix increment (pre-increment) | ||
+ | @2@ prefix decrement (pre-decrement) | ||
====Built-in prefix operators==== | ====Built-in prefix operators==== | ||
− | + | @1@ The expression {{c|++x}} is equivalent to {{c|1=x += 1}}, with the following exceptions: | |
− | {{ | + | {{rev begin}} |
− | {{ | + | {{rev|until=c++17| |
− | {{ | + | * If the type of {{spar|expression}} is (possibly volatile-qualified) {{c/core|bool}}, {{spar|expression}} is set to {{c|true}}. Such a increment is deprecated. |
− | {{ | + | }} |
− | {{ | + | {{rev|since=c++17| |
− | {{ | + | * If the type of {{spar|expression}} is (possibly cv-qualified) {{c/core|bool}}, the program is ill-formed. |
− | {{ | + | }} |
+ | {{rev|since=c++20| | ||
+ | * If the type of {{spar|expression}} is volatile-qualified, the increment is deprecated. | ||
+ | }} | ||
+ | {{rev end}} | ||
− | The | + | @2@ The expression {{c|--x}} is equivalent to {{c|1=x -= 1}}, with the following exceptions: |
+ | * If the type of {{spar|expression}} is (possibly cv-qualified) {{c/core|bool}}, the program is ill-formed. | ||
+ | {{rrev|since=c++20| | ||
+ | * If the type of {{spar|expression}} is volatile-qualified, the decrement is deprecated. | ||
+ | }} | ||
− | {{ | + | {{anchor|Prefix overloads}} |
− | ==== | + | ====Overloads==== |
− | + | In {{rlp|overload resolution#Call to an overloaded operator|overload resolution against user-defined operators}}, for every optionally volatile-qualified arithmetic type {{tt|A}} other than {{c/core|bool}}, and for every optionally volatile-qualified pointer {{tt|P}} to optionally cv-qualified object type, the following function signatures participate in overload resolution: | |
{{dcl begin}} | {{dcl begin}} | ||
− | {{dcl | A operator++(A& | + | {{dcl|A& operator++(A&)}} |
− | {{dcl | bool operator++(bool& | + | {{dcl|bool& operator++(bool&)|notes={{mark deprecated}}{{mark until c++17}}}} |
− | {{dcl | P operator++(P& | + | {{dcl|P& operator++(P&)}} |
− | {{dcl | A operator--(A& | + | {{dcl|A& operator--(A&)}} |
− | {{dcl | P operator--(P& | + | {{dcl|P& operator--(P&)}} |
{{dcl end}} | {{dcl end}} | ||
− | The | + | ===Postfix operators=== |
+ | The postfix increment and decrement expressions have the form | ||
+ | {{sdsc begin}} | ||
+ | {{sdsc|{{spar|expression}} {{ttb|++}}}} | ||
+ | {{sdsc|{{spar|expression}} {{ttb|--}}}} | ||
+ | {{sdsc end}} | ||
+ | @1@ postfix increment (post-increment) | ||
+ | @2@ postfix decrement (post-decrement) | ||
− | If the operand of the | + | ====Built-in postfix operators==== |
+ | The result of postfix increment or decrement is a prvalue copy of {{spar|expression}} before modification. The type of the result is the cv-unqualified version of the type of {{spar|expression}}. | ||
+ | |||
+ | If {{spar|expression}} is not a modifiable lvalue of an arithmetic type{{rev inl|since=c++17| other than (possibly cv-qualified) {{c/core|bool}}}}, or a pointer to a complete object type, the program is ill-formed. | ||
+ | |||
+ | {{rrev|since=c++20| | ||
+ | If the type of {{spar|expression}} is volatile-qualified, the increment or decrement is deprecated. | ||
+ | }} | ||
+ | |||
+ | @1@ The value of {{spar|expression}} is modified as if it were the operand of the prefix {{tt|++}} operator. | ||
+ | |||
+ | @2@ The value of {{spar|expression}} is modified as if it were the operand of the prefix {{tt|--}} operator. | ||
+ | |||
+ | The value computation of a postfix increment or decrement is {{rlp|eval order|sequenced before}} the modification of {{spar|expression}}. With respect to an indeterminately-sequenced function call, the operation of a postfix increment or decrement is a single evaluation. | ||
+ | |||
+ | {{anchor|Postfix overloads}} | ||
+ | ====Overloads==== | ||
+ | In {{rlp|overload resolution#Call to an overloaded operator|overload resolution against user-defined operators}}, for every optionally volatile-qualified arithmetic type {{tt|A}} other than {{c/core|bool}}, and for every optionally volatile-qualified pointer {{tt|P}} to optionally cv-qualified object type, the following function signatures participate in overload resolution: | ||
+ | {{dcl begin}} | ||
+ | {{dcl|A operator++(A&, int)}} | ||
+ | {{dcl|bool operator++(bool&, int)|notes={{mark deprecated}}{{mark until c++17}}}} | ||
+ | {{dcl|P operator++(P&, int)}} | ||
+ | {{dcl|A operator--(A&, int)}} | ||
+ | {{dcl|P operator--(P&, int)}} | ||
+ | {{dcl end}} | ||
====Example==== | ====Example==== | ||
{{example | {{example | ||
− | + | |code= | |
− | + | ||
#include <iostream> | #include <iostream> | ||
Line 95: | Line 137: | ||
<< "n4 = " << n4 << '\n'; | << "n4 = " << n4 << '\n'; | ||
} | } | ||
− | + | |output= | |
n1 = 5 | n1 = 5 | ||
n2 = 2 | n2 = 2 | ||
Line 103: | Line 145: | ||
===Notes=== | ===Notes=== | ||
− | Because of the side-effects involved, built-in increment and decrement operators must be used with care to avoid undefined behavior due to violations of | + | Because of the side-effects involved, built-in increment and decrement operators must be used with care to avoid undefined behavior due to violations of {{rlp|eval order|sequencing rules}}. |
− | Because a temporary copy of the object is constructed during post-increment and post-decrement, | + | Because a temporary copy of the object is constructed during post-increment and post-decrement, pre-increment or pre-decrement operators are usually more efficient in contexts where the returned value is not used. |
===Standard library=== | ===Standard library=== | ||
− | Increment and decrement operators are overloaded for many standard library types. In particular, every {{ | + | Increment and decrement operators are overloaded for many standard library types. In particular, every {{named req|Iterator}} overloads {{c/core|operator++}} and every {{named req|BidirectionalIterator}} overloads {{c/core|operator--}}, even if those operators are no-ops for the particular iterator. |
{{dsc begin}} | {{dsc begin}} | ||
− | {{dsc h2 | overloads for arithmetic types}} | + | {{dsc h2|overloads for arithmetic types}} |
− | {{dsc inc | cpp/atomic/atomic/dsc | + | {{dsc inc|cpp/atomic/atomic/dsc operator arith}} |
− | {{dsc inc | cpp/chrono/duration/dsc | + | {{dsc inc|cpp/chrono/duration/dsc operator arith2}} |
− | {{dsc h2 | overloads for iterator types}} | + | {{dsc h2|overloads for iterator types}} |
− | {{dsc inc | cpp/memory/raw_storage_iterator/dsc | + | {{dsc inc|cpp/memory/raw_storage_iterator/dsc operator arith}} |
− | {{dsc inc | cpp/iterator/adaptor/dsc | + | {{dsc inc|cpp/iterator/adaptor/dsc operator arith|reverse_iterator}} |
− | {{dsc inc | cpp/iterator/adaptor/dsc | + | {{dsc inc|cpp/iterator/adaptor/dsc operator arith|move_iterator}} |
− | {{dsc inc | cpp/iterator/inserter/dsc | + | {{dsc inc|cpp/iterator/inserter/dsc operator arith|front_insert_iterator}} |
− | {{dsc inc | cpp/iterator/inserter/dsc | + | {{dsc inc|cpp/iterator/inserter/dsc operator arith|back_insert_iterator}} |
− | {{dsc inc | cpp/iterator/inserter/dsc | + | {{dsc inc|cpp/iterator/inserter/dsc operator arith|insert_iterator}} |
− | {{dsc inc | cpp/iterator/istream_iterator/dsc | + | {{dsc inc|cpp/iterator/istream_iterator/dsc operator arith}} |
− | {{dsc inc | cpp/iterator/ostream_iterator/dsc | + | {{dsc inc|cpp/iterator/ostream_iterator/dsc operator arith}} |
− | {{dsc inc | cpp/iterator/istreambuf_iterator/dsc | + | {{dsc inc|cpp/iterator/istreambuf_iterator/dsc operator arith}} |
− | {{dsc inc | cpp/iterator/ostreambuf_iterator/dsc | + | {{dsc inc|cpp/iterator/ostreambuf_iterator/dsc operator arith}} |
− | {{dsc inc | cpp/regex/regex_iterator/dsc | + | {{dsc inc|cpp/regex/regex_iterator/dsc operator arith}} |
− | {{dsc inc | cpp/regex/regex_token_iterator/dsc | + | {{dsc inc|cpp/regex/regex_token_iterator/dsc operator arith}} |
{{dsc end}} | {{dsc end}} | ||
+ | |||
+ | ===Defect reports=== | ||
+ | {{dr list begin}} | ||
+ | {{dr list item|wg=cwg|dr=2855|std=C++98|before=usual arithmetic conversions are applied for pre-increment and<br>pre-decrement, but were not applied to their postfix counterparts<ref>The prefix {{c|++x}} is equivalent to {{c|1=x += 1}}, and the latter is applicable for usual arithmetic conversions (i.e. yield a common type between {{c/core|decltype(x)}} and {{c/core|int}}). However, the effect of the postfix {{c|x++}} is simply “adding one to {{c|x}}”, there is no binary operator present, so no usual arithmetic conversions will take place.</ref>|after=also applied}} | ||
+ | {{dr list end}} | ||
+ | <references/> | ||
===See also=== | ===See also=== | ||
− | + | {{rlp|operator precedence|Operator precedence}} | |
− | + | {{rlp|operators|Operator overloading}} | |
{{cpp/language/operators}} | {{cpp/language/operators}} | ||
+ | {{dsc begin}} | ||
+ | {{dsc see c|c/language/operator incdec|Increment/decrement operators|nomono=true}} | ||
+ | {{dsc end}} | ||
− | + | {{langlinks|de|es|fr|it|ja|pt|ru|zh}} | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + |
Latest revision as of 13:30, 14 August 2024
Increment/decrement operators increment or decrement the value of the object.
Operator name | Syntax | Overloadable | Prototype examples (for class T) | |
---|---|---|---|---|
Inside class definition | Outside class definition | |||
pre-increment | ++a
|
Yes | T& T::operator++(); | T& operator++(T& a); |
pre-decrement | --a
|
Yes | T& T::operator--(); | T& operator--(T& a); |
post-increment | a++
|
Yes | T T::operator++(int); | T operator++(T& a, int); |
post-decrement | a--
|
Yes | T T::operator--(int); | T operator--(T& a, int); |
|
Contents |
[edit] Prefix operators
The prefix increment and decrement expressions have the form
++ expression
|
|||||||||
-- expression
|
|||||||||
[edit] Built-in prefix operators
|
(until C++17) |
|
(since C++17) |
|
(since C++20) |
- If the type of expression is (possibly cv-qualified) bool, the program is ill-formed.
|
(since C++20) |
[edit] Overloads
In overload resolution against user-defined operators, for every optionally volatile-qualified arithmetic type A
other than bool, and for every optionally volatile-qualified pointer P
to optionally cv-qualified object type, the following function signatures participate in overload resolution:
A& operator++(A&) |
||
bool& operator++(bool&) |
(deprecated)(until C++17) | |
P& operator++(P&) |
||
A& operator--(A&) |
||
P& operator--(P&) |
||
[edit] Postfix operators
The postfix increment and decrement expressions have the form
expression ++
|
|||||||||
expression --
|
|||||||||
[edit] Built-in postfix operators
The result of postfix increment or decrement is a prvalue copy of expression before modification. The type of the result is the cv-unqualified version of the type of expression.
If expression is not a modifiable lvalue of an arithmetic type other than (possibly cv-qualified) bool(since C++17), or a pointer to a complete object type, the program is ill-formed.
If the type of expression is volatile-qualified, the increment or decrement is deprecated. |
(since C++20) |
++
operator.--
operator.The value computation of a postfix increment or decrement is sequenced before the modification of expression. With respect to an indeterminately-sequenced function call, the operation of a postfix increment or decrement is a single evaluation.
[edit] Overloads
In overload resolution against user-defined operators, for every optionally volatile-qualified arithmetic type A
other than bool, and for every optionally volatile-qualified pointer P
to optionally cv-qualified object type, the following function signatures participate in overload resolution:
A operator++(A&, int) |
||
bool operator++(bool&, int) |
(deprecated)(until C++17) | |
P operator++(P&, int) |
||
A operator--(A&, int) |
||
P operator--(P&, int) |
||
[edit] Example
#include <iostream> int main() { int n1 = 1; int n2 = ++n1; int n3 = ++ ++n1; int n4 = n1++; // int n5 = n1++ ++; // error // int n6 = n1 + ++n1; // undefined behavior std::cout << "n1 = " << n1 << '\n' << "n2 = " << n2 << '\n' << "n3 = " << n3 << '\n' << "n4 = " << n4 << '\n'; }
Output:
n1 = 5 n2 = 2 n3 = 4 n4 = 4
[edit] Notes
Because of the side-effects involved, built-in increment and decrement operators must be used with care to avoid undefined behavior due to violations of sequencing rules.
Because a temporary copy of the object is constructed during post-increment and post-decrement, pre-increment or pre-decrement operators are usually more efficient in contexts where the returned value is not used.
[edit] Standard library
Increment and decrement operators are overloaded for many standard library types. In particular, every LegacyIterator overloads operator++ and every LegacyBidirectionalIterator overloads operator--, even if those operators are no-ops for the particular iterator.
overloads for arithmetic types | |
increments or decrements the atomic value by one (public member function of std::atomic<T> )
| |
increments or decrements the tick count (public member function of std::chrono::duration<Rep,Period> )
| |
overloads for iterator types | |
advances the iterator (public member function of std::raw_storage_iterator<OutputIt,T> )
| |
advances or decrements the iterator (public member function of std::reverse_iterator<Iter> )
| |
advances or decrements the iterator (public member function of std::move_iterator<Iter> )
| |
no-op (public member function of std::front_insert_iterator<Container> )
| |
no-op (public member function of std::back_insert_iterator<Container> )
| |
no-op (public member function of std::insert_iterator<Container> )
| |
advances the iterator (public member function of std::istream_iterator<T,CharT,Traits,Distance> )
| |
no-op (public member function of std::ostream_iterator<T,CharT,Traits> )
| |
advances the iterator (public member function of std::istreambuf_iterator<CharT,Traits> )
| |
no-op (public member function of std::ostreambuf_iterator<CharT,Traits> )
| |
advances the iterator to the next match (public member function of std::regex_iterator<BidirIt,CharT,Traits> )
| |
advances the iterator to the next submatch (public member function of std::regex_token_iterator<BidirIt,CharT,Traits> )
|
[edit] Defect reports
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR | Applied to | Behavior as published | Correct behavior |
---|---|---|---|
CWG 2855 | C++98 | usual arithmetic conversions are applied for pre-increment and pre-decrement, but were not applied to their postfix counterparts[1] |
also applied |
- ↑ The prefix ++x is equivalent to x += 1, and the latter is applicable for usual arithmetic conversions (i.e. yield a common type between decltype(x) and int). However, the effect of the postfix x++ is simply “adding one to x”, there is no binary operator present, so no usual arithmetic conversions will take place.
[edit] See also
Common operators | ||||||
---|---|---|---|---|---|---|
assignment | increment decrement |
arithmetic | logical | comparison | member access |
other |
a = b |
++a |
+a |
!a |
a == b |
a[...] |
function call |
a(...) | ||||||
comma | ||||||
a, b | ||||||
conditional | ||||||
a ? b : c | ||||||
Special operators | ||||||
static_cast converts one type to another related type |
C documentation for Increment/decrement operators
|