Почему оператор приращения postfix принимает фиктивный параметр?

Посмотрите на эти сигнатуры функций:

 class Number {
 public:
   Number& operator++ ();    // prefix ++
   Number  operator++ (int); // postfix ++
 }; 

Префикс не принимает никаких параметров, но postfix делает. Зачем? Я думал, что мы можем распознать их с разными типами возврата.

Ответ 1

Вы можете предоставить оператор ++ любой тип возврата, который вам нравится, поэтому нет способа отличить постфикс и префикс от этого. Поэтому компилятору нужен какой-то ключ.

OTOH, я не знаю, почему это не могло быть сделано только в синтаксисе:

//prefix
int& ++operator (); 
//postfix
int& operator++ (); 

В конце концов, имитация использования в объявлениях имеет традицию в C и С++.

P.S. Другие плакаты: Это не имеет никакого отношения к перегрузке по типу возврата. postfix и prefix ++/- это два разных имени. Нет необходимости разрешать перегрузку в x++ или ++x, потому что она полностью очищает название.

Ответ 2

Префикс и постфикс ++ - разные операторы. Со стандартным объявлением стиля Foo operator symbol(Foo &) не было очевидного способа отличить эти два. Вместо того, чтобы придумывать какой-то новый синтаксис, такой как Foo symbol operator(Foo &) который превратил бы его в особый случай, в отличие от всех других операторов, и, вероятно, немного боль, чтобы разобрать, разработчики языка хотели другого решения.

Решение, которое они выбрали, было несколько странным. Они отметили, что все остальные операторы postfix (т.е. операторы, которые произошли после одного из их операндов) были фактически инфиксными операторами, которые принимали два аргумента. Например, обычный старый +, / или >. Исходя из этого, разработчики языка решили, что наличие случайного фиктивного аргумента будет хорошим способом отличить префикс и постфикс ++.

ИМХО, это одно из странных решений, принятых как C++. Но у вас это есть.

И вы не можете отличить их по типу возврата по двум причинам.

Во-первых, функции в C++ не могут быть перегружены по типу возврата. У вас не может быть двух функций, которые имеют одинаковые имена и списки типов параметров, но разные возвращаемые значения.

Во-вторых, этот метод не будет устойчивым или достаточно гибким, чтобы обрабатывать все возможные реализации префикса и postfix ++.

Например, вам может понадобиться постфикс ++ который возвращал ссылочный тип, если единственная причина, по которой вы когда-либо вызывали его, заключалась в том, чтобы ссылаться на побочный эффект, не связанный со значением переменной, к которой вы ее применяли. На мой взгляд, это будет очень плохая реализация, но C++ не собирается судить, какой глупый код вы хотите написать, но и о том, чтобы вы могли писать любой код, который, по вашему мнению, подходит для ситуации. И заставить вас использовать один конкретный стиль возвращаемого типа для префикса ++ и postfix ++ будет противоречить этому духу.

Ответ 3

Прямо от устья Бьярна:

Это может быть слишком мило и слишком тонко, но оно работает, не требует нового синтаксиса и имеет логику безумия. Другие унарные операторы являются префиксами и не принимают аргументов, если они определены как функции-члены. Параметр "нечетный" и неиспользуемый фиктивный int используется для обозначения нечетных операторов постфикса. Другими словами, в постфиксном случае ++ происходит между первым (реальным) операндом и вторым (фиктивным) аргументом и, таким образом, является постфиксным.

Эти объяснения необходимы, потому что механизм уникален и, следовательно, немного бородавка. Учитывая выбор, я бы, вероятно, ввел ключевые слова prefix и postfix, но в то время это казалось невозможным. Однако единственный важный момент в том, что механизм работает и может быть понят и использован немногими программистами, которые действительно нуждаются в нем.

Кстати, на мой взгляд, только префикс ++ должен быть перегружен программистом, а постфикс ++ должен автоматически генерироваться компилятором. Кто-нибудь согласен со мной?

Ответ 4

Вам не разрешается перегружать функции только с помощью типа возврата, поэтому для разграничения между двумя одинаково выглядящими операторами operator++() необходим фиктивный параметр.

Ответ 5

Если бы у меня были мои барабанщики, постинкремент и многие операторы последовательности были разделены на две или три части; в случае постинкремента, утверждение типа "a = (b ++ + С++)"; было бы эффективно переведено как "a = postinc1 (b) + postinc1 (c); postinc2 (b); postinc2 (c);"; вторая часть пост-приращения будет пустой функцией. В реальной реализации вызовы postinc2() должны часто возникать, в то время как некоторые другие результаты сидят в стеке оценки; это не должно быть слишком сложно для компилятора.

В случае "& &" или "||", первая часть оператора будет действовать только на левый операнд; если он возвращает ненулевое значение (для &) или ненулевое значение (для ||), то вторая часть будет работать с обоими операндами.

В случае "?" / ":" первая часть оператора будет работать только с первым операндом. Если он возвращает ненулевое значение, вторая часть будет работать с первым и вторым параметрами; в противном случае третья часть будет работать с первым и третьим параметрами.

Есть ли на любом языке что-нибудь подобное? Кажется странным, что С++ позволяет переопределять операторы способами, которые нарушают поведение последовательности, но не позволяют их переопределять способами, которые его сохраняют.

Ответ 6

Компилятор использует аргумент int для различения операторов префикса и постфикса. Для неявных вызовов значение по умолчанию равно нулю, поэтому actully не делает так сильно различий в функциональности перегруженного оператора...