Difference between revisions of "cpp/language/operator incdec"
Andreas Krug (Talk | contribs) m (fmt) |
(Added CWG issue #2855 DR.) |
||
Line 8: | Line 8: | ||
!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 | ||
Line 39: | Line 39: | ||
|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 | The prefix increment and decrement expressions have the form | ||
{{sdsc begin}} | {{sdsc begin}} | ||
− | {{sdsc|{{ttb|++}} {{spar| | + | {{sdsc|{{ttb|++}} {{spar|expression}}}} |
− | {{sdsc|{{ttb|--}} {{spar| | + | {{sdsc|{{ttb|--}} {{spar|expression}}}} |
{{sdsc end}} | {{sdsc end}} | ||
@1@ prefix increment (pre-increment) | @1@ prefix increment (pre-increment) | ||
@2@ prefix decrement (pre-decrement) | @2@ prefix decrement (pre-decrement) | ||
− | The | + | ====Built-in prefix operators==== |
+ | @1@ The expression {{c|++x}} is equivalent to {{c|1=x += 1}}, with the following exceptions: | ||
+ | * If the type of {{spar|expression}} is volatile-qualified, the increment is deprecated. | ||
+ | {{rev begin}} | ||
+ | {{rev|until=c++17| | ||
+ | * If the type of {{spar|expression}} is (possibly volatile-qialified) {{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-qialified) {{c/core|bool}}, the program is ill-formed. | ||
+ | }} | ||
+ | {{rev end}} | ||
− | {{ | + | @2@ The expression {{c|--x}} is equivalent to {{c|1=x -= 1}}, with the following exceptions: |
+ | * If the type of {{spar|expression}} is volatile-qualified, the decrement is deprecated. | ||
+ | * If the type of {{spar|expression}} is (possibly cv-qialified) {{c/core|bool}}, the program is ill-formed. | ||
− | In {{rlp| | + | {{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&)}} | ||
Line 73: | Line 79: | ||
{{dcl end}} | {{dcl end}} | ||
− | === | + | ===Postfix operators=== |
The postfix increment and decrement expressions have the form | The postfix increment and decrement expressions have the form | ||
{{sdsc begin}} | {{sdsc begin}} | ||
− | {{sdsc|{{spar| | + | {{sdsc|{{spar|expression}} {{ttb|++}}}} |
− | {{sdsc|{{spar| | + | {{sdsc|{{spar|expression}} {{ttb|--}}}} |
{{sdsc end}} | {{sdsc end}} | ||
@1@ postfix increment (post-increment) | @1@ postfix increment (post-increment) | ||
@2@ postfix decrement (post-decrement) | @2@ postfix decrement (post-decrement) | ||
− | 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. | ||
+ | |||
+ | @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. | |
− | In {{rlp| | + | {{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 begin}} | ||
{{dcl|A operator++(A&, int)}} | {{dcl|A operator++(A&, int)}} | ||
Line 121: | Line 136: | ||
===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 {{rlp| | + | 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 {{named req|Iterator}} overloads operator++ and every {{named req|BidirectionalIterator}} overloads operator--, even if those operators are no-ops for the particular iterator. | + | 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=== |
Revision as of 00:59, 25 June 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 |
Prefix operators
The prefix increment and decrement expressions have the form
++ expression
|
|||||||||
-- expression
|
|||||||||
Built-in prefix operators
- If the type of expression is volatile-qualified, the increment is deprecated.
|
(until C++17) |
|
(since C++17) |
- If the type of expression is volatile-qualified, the decrement is deprecated.
- If the type of expression is (possibly cv-qialified) bool, the program is ill-formed.
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&) |
||
Postfix operators
The postfix increment and decrement expressions have the form
expression ++
|
|||||||||
expression --
|
|||||||||
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.
++
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.
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) |
||
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
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.
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> )
|
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.
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
|