重载递减运算符时使用的额外参数是什么?

What is the extra argument used for when overloading the decrement operator?

当我重载 post-递减运算符时,我必须包含一个额外的参数:

#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;
}

如果删除这个看似不需要的参数,则会出现编译错误:

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

这个参数有什么用?它的值代表什么?

因为您使用的是后缀递减:

 while (i-- > 0)

应该减少 i 但 return 原始值:

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

虚拟int参数只是一个占位符,用于区分后缀和前缀递减:

T operator--() // no param for prefix
{
    value -= 1;
    return value;
}

来自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)).

虽然我强烈建议不要围绕这些显式调用创建功能(对于其他任何人来说,这看起来会非常奇怪)。

operator++ - pre-increment and post-increment 有两个独立但相关的重载。两者都是可覆盖的。由于它们具有相同的名称,C++ 的设计者必须决定一种语法,让编译器区分它们。他们选择在 post 增量运算符上使用虚拟 int 参数。

当你这样写代码时:

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

编译器发出代码来调用无参数 operator++()

当您编写这样的代码时:

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

编译器发出代码来调用带参数的 operator++(int),为虚拟参数传递 0

参数的 value 没有意义,它的存在足以让 operator++ 的每个重载被单独覆盖,因为它们具有不同的签名。

顺便说一句,同样的规则也适用于 pre/post-decrement operator--

每个已批准的 ANSI 和 ISO C++ 标准以及每个工作草案都对此进行了描述,尽管版本之间的精确措辞有所不同。

例如,根据 "Working Draft, Standard for Programming Language C++",文档编号 N4659,日期为 2017-03-21,第 16.5.7 节 "Increment and decrement [over.inc]",第 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.

在上一段的末尾,有对脚注 134 的引用,其中说

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

在第 1 段之后,标准甚至提供了示例。

[ 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 ]

第2段接着说

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