60

Can we overload operator++ for pre-increment and post-increment? i.e. calling SampleObject++ and ++SampleObject gives the correct results.

class CSample { public: int m_iValue; // just to directly fetch inside main() CSample() : m_iValue(0) {} CSample(int val) : m_iValue(val) {} // Overloading ++ for Pre-Increment int /*CSample& */ operator++() { // can also adopt to return CSample& ++(*this).m_iValue; return m_iValue; /*(*this); */ } // Overloading ++ for Post-Increment /* int operator++() { CSample temp = *this; ++(*this).m_iValue; return temp.m_iValue; /* temp; */ } */ }; 

We can't overload a function based only on return type, and also even if we take it as permitted, it doesn't solve the problem because of the ambiguity in overload resolution.

Since operator overloading is provided to make built-in types behave like user-defined types, why can't we avail of both pre and post increment for our own types at the same time?

3
  • Personally, I never implement or write post increment. IMO its use can lead to very complicated code. Commented Mar 6, 2013 at 10:09
  • 2
    @LCIDFire it would be quite tricky to implement iterators without it. Commented Mar 6, 2013 at 10:11
  • With C++20, you get default comparisons (a.k.a. "spaceship operator"). Commented Sep 28, 2020 at 9:18

4 Answers 4

111

The postfix version of the increment operator takes a dummy int parameter in order to disambiguate:

// prefix CSample& operator++() { // implement increment logic on this instance, return reference to it. return *this; } // postfix CSample operator++(int) { CSample tmp(*this); operator++(); // prefix-increment this instance return tmp; // return value before increment } 
Sign up to request clarification or add additional context in comments.

7 Comments

but how compiler does this mapping as we don't pass any parameter (int) while using ++.
@ajay it is defined in the language. When you call i++, it will pick version operator++(int). It is a bit of a hack, bit that is the way it is done.
When overloading a function (i.e. having two different functions with the same name) the compiler can't tell them apart based on just the return type, the thing that tells them apart is the number and type of arguments passed to them. This is why the postfix increment has an int argument "artificially" added.
In an ordinary function destructor of the CSample will be called after returning from the function. Does that not happen in post operator overload?
@paarandika Copies from values returned from functions may be elided, in which case there would be no copy constructor or destructor calls. But if the copy isn't elided, then formally there will be a destructor call (modulo trivially destructible types and the as-if rule.)
|
30

The standard pattern for pre-increment and post-increment for type T

T& T::operator++() // pre-increment, return *this by reference { // perform operation return *this; } T T::operator++(int) // post-increment, return unmodified copy by value { T copy(*this); ++(*this); // or operator++(); return copy; } 

(You can also call a common function for performing the increment, or if it's a simple one-liner like ++ on a member, just do it in both)

Comments

13

why we can't avail both pre and post increment for our own types at the same time.

You can:

class CSample { public: int m_iValue; CSample() : m_iValue(0) {} CSample(int val) : m_iValue(val) {} // Overloading ++ for Pre-Increment int /*CSample& */ operator++() { ++m_iValue; return m_iValue; } // Overloading ++ for Post-Increment int operator++(int) { int value = m_iValue; ++m_iValue; return value; } }; #include <iostream> int main() { CSample s; int i = ++s; std::cout << i << std::endl; // Prints 1 int j = s++; std::cout << j << std::endl; // Prints 1 } 

Comments

9

[N4687]

16.5.7

The user-defined function called operator++ implements the prefix and postfix ++ operator. If this function is a non-static member function with no parameters, or a non-member function with one parameter, it defines the prefix increment operator++ for objects of that type. If the function is a non-static member function with one parameter (which shall be of type int) or a non-member function with two parameters (the second of which shall be of type int), it defines the postfix increment operator ++ for objects of that type. When the postfix increment is called as a result of using the ++ operator, the int argument will have value zero

Example:

struct X { X& operator++(); // prefix ++a X operator++(int); // postfix a++ }; struct Y { }; Y& operator++(Y&); // prefix ++b Y operator++(Y&, int); // postfix b++ void f(X a, Y b) { ++a; // a.operator++(); a++; // a.operator++(0); ++b; // operator++(b); b++; // operator++(b, 0); a.operator++(); // explicit call: like ++a; a.operator++(0); // explicit call: like a++; operator++(b); // explicit call: like ++b; operator++(b, 0); // explicit call: like b++; } 

2 Comments

what happens with (b++2)?
@AnnoyinC this can't compile even when b is int. godbolt.org/z/dEPzM8Whh

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.