Почему Postfix ++ / - классифицируется как основные операторы в C #? - PullRequest
14 голосов
/ 13 августа 2011

В настоящее время я преподаю классу программистов C ++ основы языка C #. Когда мы обсуждали тему операторов, я использовал стандартные категории C # основных, унарных и т. Д. Операторов.

Один из участников был озадачен, потому что в стандарте C # «постфикс ++ / -» был помещен в категорию первичных операторов, а не в «префикс ++ / -». Ее путаница заключалась в том, что она предпочла бы реализовать оператор C ++ "postfix ++ / -" в терминах оператора "prefix ++ / -". Другими словами, она предпочла бы считать оператор "префикс ++ / -" основным оператором. - Я понимаю ее точку зрения, но я не могу дать ей обоснование этого. ОК, операторы "postfix ++ / -" имеют более высокий приоритет, чем "prefix ++ / -", но является ли это единственным обоснованием этого?

В спецификации упоминается об этом в разделе "14.2.1 Приоритет и ассоциативность операторов".

Итак, мой очень нейтральный вопрос: почему Postfix ++ / классифицируется как основной оператор в C #? Есть ли в этом более глубокая правда?

Ответы [ 3 ]

2 голосов
/ 13 августа 2011

Поскольку сам стандарт ECMA не определяет, что такое «первичный» оператор, кроме порядка старшинства (т. Е. Перед «унарным»), не может быть никакого другого значения.Выбор слов, вероятно, был неудачным.

Примите во внимание, что во многих языках C-link постфиксные операторы имеют тенденцию создавать временную переменную, в которой хранится промежуточный результат выражения (см .: "Предпочитают префиксные операторычерез постфикс "в точке с запятой ).Таким образом, они принципиально отличаются от префиксной версии.

Тем не менее, быстро проверяя, как Mono и Visual Studio компилируют циклы for с использованием постфиксных и префиксных форм, я увидел, что полученный код IL идентичен.Только если вы используете значение выражения postfix / prefix, оно преобразуется в другой IL (влияет только на то место, где помещена инструкция 'dup'), по крайней мере с упомянутыми реализациями.

2 голосов
/ 13 августа 2011

РЕДАКТИРОВАТЬ: Хорошо, теперь я вернулся домой, я удалил большинство запутанных частей ...

Я не знаю, почему x++ классифицируется как первичное выражение, а ++x - нет; хотя я сомневаюсь, что это имеет большое значение с точки зрения кода, который вы бы написали. То же самое. Интересно, считается ли постфикс основным, так как он используется чаще? Аннотированные спецификации C # не имеют никаких аннотаций по этому поводу, кстати, ни в версии ECMA, ни в версиях Microsoft C # 4. (Я не могу сразу найти свой выпуск C # 3 для проверки.)

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

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

РЕДАКТИРОВАТЬ: Просто чтобы дать еще один комментарий, даже если это кажется произвольным, я согласен, что это кажется странным, когда спецификация заявляет:

Первичные выражения включают простейшие формы выражений

Но список шагов для преинкремента короче / проще, чем список шагов для постинкремента (так как он не включает шаг «сохранить значение»).

1 голос
/ 16 ноября 2012

разница в том, что [i ++] будет обращаться к индексируемому элементу i.

a [++ i] будет обращаться к индексируемому элементу i + 1.

В обоих случаях после выполнения[++ i / i ++]

я буду i + 1.

Это может создать проблемы, потому что вы не можете сделать предположение о параметре order

function (i ++, i ++, i ++)

увеличит i в 3 раза, но вы не знаете, в каком порядке.если изначально я равен 4, вы также можете иметь функцию (4,5,6)

, но также функцию (6,5,4) или также функцию (6,4,5).

и это все еще ничего, потому что я использовал в качестве примера нативные типы (например, "int"), когда у вас есть классы, дела идут хуже.

Когда перегрузка оператора не изменяется, то меняется его приоритет.и это тоже может вызвать проблемы.

Таким образом, в одном случае «++» применяется перед возвратом ссылки, в другом случае применяется «после» возврата ссылки.И когда вы перегружаете его, вероятно, лучше применить его перед возвратом в ссылку (поэтому ++ что-то намного лучше чем что-то ++, по крайней мере, с точки зрения перегрузки.)

взять универсальный класс с перегруженным ++ (изу нас есть 2 элемента, foo и bar)

    foo = bar ++; //is like writing (foo=bar).operator++();

    foo = ++bar; // is like writing foo= (bar.operator++());

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...