Почему оператор приращения postfix принимает фиктивный параметр? - PullRequest
20 голосов
/ 26 августа 2010

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

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

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

Ответы [ 6 ]

10 голосов
/ 26 августа 2010

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

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

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

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

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

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

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

8 голосов
/ 26 августа 2010

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

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

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

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

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

7 голосов
/ 26 августа 2010

Прямо из уст Бьярне:

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

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

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

2 голосов
/ 26 августа 2010

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

0 голосов
/ 23 ноября 2013

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

0 голосов
/ 17 сентября 2010

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

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

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

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

...