-1

When I overload the post-decrement operator, I have to include a extra argument:

#include <iostream>

template<class T>
class wrap
{
public:
    bool operator >(T &&v)
    {
        return value > v;
    }
    T operator --(int v) // Remove 'int v' and you get a compilation error
    {
        return (value -= 1) + 1;
    }
    wrap(T v)
    {
        value = v;
    }
private:
    T value;
};

int main(void)
{
    wrap<int> i(5);
    while(i --> 0)
        std::cout << "Why do we need the extra argument?\n";
    return 0;
}

If I remove this seemingly unneeded argument, I get a compilation error:

test.cpp: In function ‘int main()’:
test.cpp:26:13: error: no ‘operator--(int)’ declared for postfix ‘--’ [-fpermissive]
     while(i --> 0)
           ~~^~

What is this argument used for? What does its value represent?

S.S. Anne
  • 15,171
  • 8
  • 38
  • 76

4 Answers4

2

There are two separate but related overloads of operator++ - pre-increment and post-increment. Both are overridable. Since they both have the same name, the designers of C++ had to decide on a syntax to let the compiler differentiate between them. They chose to use a dummy int parameter on the post-increment operator.

When you write code like this:

wrap<int> i(5);
++i; // <-- calls i.operator++();

The compiler emits code to call the parameter-less operator++().

When you write code like this instead:

wrap<int> i(5);
i++; // <-- calls i.operator++(0);

The compiler emits code to call the parametered operator++(int), passing 0 for the dummy parameter.

The value of the parameter is meaningless, its mere presence is enough to let each overload of operator++ be overriden individually since they have different signatures.

BTW, the same rules apply to the pre/post-decrement operator-- as well.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • does this mean that a slight additional overhead is incurred by calling `my++` versus `++my`? – Patrick Parker Jan 01 '20 at 07:00
  • @PatrickParker yes, due to the extra parameter being pushed/popped on the call stack, and also because post-increment also returns a copy of the old value before it was incremented. Pre-increment returns a reference to the incremented value, not a copy – Remy Lebeau Jan 01 '20 at 09:08
2

Every ratified ANSI and ISO C++ standard, and every working draft, describes this, although the precise wording changes between versions.

For example, according to the "Working Draft, Standard for Programming Language C++", document number N4659, dated 2017-03-21, Section 16.5.7 "Increment and decrement [over.inc]", para 1

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.

At the end of the preceding para, there is a reference to footnote 134, which says

Calling operator++ explicitly, as in expressions like a.operator++(2), has no special properties: The argument to operator++ is 2.

After para 1, the standard even provides an example.

[ 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++;
}

end example ]

Para 2 then goes on to say

The prefix and postfix decrement operators -- are handled analogously.

Peter
  • 35,646
  • 4
  • 32
  • 74
1

From cppreference:

The 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., a.operator++(2) or operator++(a, 2)).

Though I would highly advise against making functionality around those explicit calls (as to anyone else it'll look extremely weird).

scohe001
  • 15,110
  • 2
  • 31
  • 51
  • What does the ISO C++ standard say on this? I'm not using Microsoft's compiler. – S.S. Anne Dec 31 '19 at 22:14
  • 1
    @JL2210 C++ standard agrees--this is a core aspect of the language. I was just lazy and chose MS since they were high on the google list. I've edited to use cppreference though, which is probably a better source anyways. – scohe001 Dec 31 '19 at 22:18
  • Can I accept another answer? Some of the others go into slightly more detail. – S.S. Anne Jan 01 '20 at 16:40
  • @JL2 the system will let you unaccept mine and accept another if you feel another answer better answers your question/solves your problem. You don't need my permission! :) – scohe001 Jan 01 '20 at 18:52
  • OK. Just didn't want to make anybody mad. – S.S. Anne Jan 01 '20 at 19:01
0

Because you're using postfix decrement:

 while (i-- > 0)

which should decrement i but return the original value:

T operator--(int) // dummy int param for postfix
{
    T temp = value;
    value -= 1;
    return temp;
}

the dummy int parameter is just a placeholder to distinguish between postfix and the prefix decrement:

T operator--() // no param for prefix
{
    value -= 1;
    return value;
}
Paul Evans
  • 27,315
  • 3
  • 37
  • 54