Имеет ли смысл ассоциативность унарных операторов?

Таблица приоритетов операторов C++ из http://en.cppreference.com/w/cpp/language/operator_precedence (я знаю, что это не является нормативным, но в стандарте не говорится о приоритете или ассоциативности) унарные операторы помечаются как правые/левые ассоциативные.

После обсуждения другого вопроса у меня остались сомнения. Имеет ли смысл ассоциативность унарных операторов?


person Luchian Grigore    schedule 18.10.2012    source источник
comment
см. мой ответ здесь (stackoverflow.com/a/14084830/1740808) с примером гипотетического языка с левоассоциативным префиксом операторы   -  person SergeyS    schedule 30.12.2012


Ответы (4)


Это просто артефакт того, как ассоциативность выводится из грамматики.

Причина того, что сложение является левоассоциативным, заключается в том, что одним из продуктов для аддитивного-выражения является аддитивное-выражение + мультипликативное-выражение , с аддитивным выражением слева. Итак, когда вы видите:

a + b + c

это должно быть эквивалентно (a + b) + c, потому что единственный способ сопоставить продукцию — использовать a + b в качестве аддитивного-выражения и c в качестве мультипликативного-выражения. a само по себе является аддитивным-выражением, но b + c не является мультипликативным-выражением, и поэтому a + b + c не соответствует произведению, если мы попытаемся взять a в качестве < em>аддитивное-выражение.

Если вы еще этого не сделали, я рекомендую вам прочитать главу «Выражения», игнорируя семантику: смотрите только на грамматические постановки. Тогда вы увидите, как старшинство и ассоциативность определяются грамматикой. Большой трюк заключается в том, что каждый тип выражения с «высоким приоритетом» ЯВЛЯЕТСЯ типом выражения с «низким приоритетом». Таким образом, каждое мультипликативное-выражение является аддитивным-выражением, но не наоборот, и это то, что делает умножение "более тесным", чем сложение.

Префиксные унарные операторы определены в грамматике следующим образом: унарное-выражение: ++ приведенное-выражение и т. д., с оператором слева для префикса и справа для постфикс. Другими словами, мы «вставляем скобки» слева для постфикса и справа для префикса. То есть мы можем сказать, что группировка осуществляется слева направо для постфиксных операторов и справа налево для префиксных операторов. И действительно, стандарт C++ говорит именно об этом (5.2/1 и 5.3/1 в C++03). Это может быть злоупотреблением терминологией или, по крайней мере, новой чеканкой, чтобы называть эту унарную группировку «ассоциативностью». Но это не главное, так как очевидно, что следует иметь в виду.

Единственная разница между бинарными и унарными операторами заключается в том, что синтаксис все равно имел бы смысл, если бы бинарные операторы группировались в противоположном направлении, поэтому a - b - c означает a - (b - c). Это было бы удивительно, но иначе не повлияло бы на язык. С унарными операторами было бы более чем неожиданно сгруппировать !!a как (!!)a, язык также должен был бы предоставить значение для подвыражения !!, которого в настоящее время у него нет. Функциональный язык мог бы дать ему значение: !! может означать функцию, состоящую из ! и !, то есть ту же операцию, что и static_cast<bool>(), но C++ не имеет концепции составления функций или операторов. Причина, по которой С++ не должен предоставлять это значение, заключается в том, что ! "группирует справа налево". Что (из-за большого трюка в грамматике) является просто еще одним способом сказать, что !! не является синтаксически правильным выражением, поэтому никогда не является подвыражением чего-либо.

Так что да, имеет смысл сказать, что префиксные операторы группируются справа налево, а постфиксные операторы группируются слева направо. Но также «очевидно», что так и должно быть, потому что мы знаем о языке C++ другие вещи.

Кстати, я думаю, что с технической точки зрения, по крайней мере, в C++, постфикс ++ не унарный оператор. Это постфиксный оператор. Но на самом деле это не имеет значения, за исключением того, что это терминология в стандарте, потому что, очевидно, это оператор и у него один операнд, как и «унарный» в английском языке.

person Steve Jessop    schedule 18.10.2012
comment
см. мой ответ здесь ( stackoverflow.com/a/14084830/1740808 ) с примером гипотетического языка с левоассоциативными префиксными операторами - person SergeyS; 30.12.2012

Ассоциативность оператора в случае унарных операторов просто определяет, на какой стороне операнда появляется оператор.

person Seth Carnegie    schedule 18.10.2012
comment
@LuchianGrigore, и это разные операторы. - person Seth Carnegie; 18.10.2012
comment
Ах, да, они появляются 2 раза - суффикс перед префиксом. - person Luchian Grigore; 18.10.2012
comment
так, в сухом остатке, они ассоциативны, только не в том же смысле, что и остальные? - person Luchian Grigore; 18.10.2012
comment
@LuchianGrigore да, потому что у них не может быть такой же неоднозначности, как у бинарных операторов, но вам нужно выяснить, к какому операнду применяется унарный оператор, когда он находится между двумя возможными операндами. - person Seth Carnegie; 18.10.2012
comment
Можете ли вы привести пример двусмысленности? - person Luchian Grigore; 18.10.2012
comment
@LuchianGrigore двусмысленность, о которой я говорю, - это когда у вас есть a - b - c, это (a - b) - c или a - (b - c)? Эти двое могут дать разные ответы. Правила ассоциативности говорят, что это (a - b) - c, поскольку - является левоассоциативным. - person Seth Carnegie; 18.10.2012
comment
@LuchianGrigore, рассмотри a + b + c и a = b = c. Они сгруппированы по-разному, потому что + левоассоциативный, а = правоассоциативный. С другой стороны, есть только один способ разобрать + + i. - person avakar; 18.10.2012
comment
Да, но в данном случае - является двоичным. Я говорю об unray. Как вы сказали, но вам нужно выяснить, к какому операнду применяется унарный оператор, когда он находится между двумя возможными операндами. - person Luchian Grigore; 18.10.2012
comment
@avakar, это я знаю, но это не унарно. - person Luchian Grigore; 18.10.2012
comment
@LuchianGrigore, извините, я думал, вы спрашиваете о той же двусмысленности, что и бинарные операторы. - person avakar; 18.10.2012
comment
С унарными операторами никогда не бывает двусмысленности. Если унарный оператор стоит между двумя операндами, всегда должен быть другой бинарный оператор слева или справа от унарного, и в этот момент унарный оператор связывается с правым или левым операндом соответственно. - person avakar; 18.10.2012
comment
@LuchianGrigore Поскольку операторы представлены одними и теми же символами, оператор действительно определяется ассоциативностью. Например, компилятор знает, что a++ является допустимым синтаксисом для постинкремента a, а не какой-то недопустимый синтаксис преинкремента, потому что преинкремент является правоассоциативным и справа не с чем ассоциироваться. - person Seth Carnegie; 18.10.2012
comment
@SethCarnegie, это еще не полный пример, и вы, кажется, противоречите авакару. - person Luchian Grigore; 18.10.2012
comment
@LuchianGrigore Как я ему противоречу? И я не имел в виду, что вы можете придумать двусмысленное выражение, я имею в виду, что двусмысленность разрешается путем придания операторам ассоциативности. - person Seth Carnegie; 18.10.2012
comment
Но ты только что сказал, что двусмысленности не о чем говорить... :( Я растерялся. - person Luchian Grigore; 18.10.2012
comment
@LuchianGrigore, если мы скажем, что постинкремент является левоассоциативным, то мы знаем, что всякий раз, когда мы видим x--, это постинкремент. То же самое касается и других унарных операторов. Это так просто. Вы не получаете оператор, а затем рассматриваете ассоциативность, как вы делаете с бинарными операторами, вы рассматриваете ассоциативность и из нее получаете оператор. - person Seth Carnegie; 18.10.2012
comment
@LuchianGrigore, ты умнее меня, поэтому, если ты запутался, я, вероятно, тоже, но я просто еще этого не знаю. - person Seth Carnegie; 18.10.2012
comment
@LuchianGrigore, возможно, кому-то еще придется объяснить или исправить меня, если это все еще не имеет смысла. - person Seth Carnegie; 18.10.2012
comment
Другой способ взглянуть на это так: когда ваш анализатор рекурсивного спуска встречает последовательность токенов {++, a}, он сначала пытается сопоставить ее как постфиксное выражение, терпит неудачу, затем пытается сопоставить ее как унарное выражение и преуспевает. Напротив, синтаксический анализатор приоритета операторов (например, алгоритм маневровой станции) явно помечает операторы их приоритетом и ассоциативностью. Я не уверен, как на практике вы справляетесь с неоднозначными токенами, такими как ++, которые могут ссылаться на два разных унарных оператора в синтаксическом анализаторе приоритета операторов, вероятно, как то, что говорит Сет. Я не силен в парсерах. - person Steve Jessop; 19.10.2012
comment
@SteveJessop в TDOP вы также просто оглядываетесь, и если есть что-то слева или что-то справа, это определяет, что такое оператор. - person Seth Carnegie; 19.10.2012

Рассмотрим следующий фрагмент кода

int *p;
*p++;

Выражение *p++ может быть оценено как (*p)++ (увеличение объекта, на который указывает p) или *(p++) (указание на следующий объект, на который указывает p).

Поскольку унарные операторы являются правоассоциативными, выражение *p++ будет оцениваться как *(p++). (Я придумал это, читая Керниган и Ричи.)

Кажется, что приоритет и ассоциативность были изменены, и постфикс ++ имеет более высокий приоритет, чем оператор разыменования *.

В соответствии с C11 приведенное выше выражение будет оцениваться как *(p++).

Я надеюсь, что это проясняет, почему унарные операторы обладают ассоциативностью.

Спасибо Lucian Grigore за указание на это.

person Shekhar Bhandakkar    schedule 12.10.2016
comment
Постфикс ассоциативен слева направо — en.cppreference.com/w/cpp/language /operator_precedence, поэтому аргумент не будет иметь места. Плюс порядок оценки в данном случае диктуется приоритетом, так как постинкремент имеет более высокий приоритет, чем разыменование. - person Luchian Grigore; 20.10.2016
comment
Спасибо за понимание. - person Shekhar Bhandakkar; 21.10.2016
comment
Я думаю, что у унарных операторов вообще нет ассоциативности, потому что один и тот же оператор не может быть связан, поэтому его следует решать с приоритетом, а не с ассоциативностью - как вы сказали, они теперь поняли. - person ; 22.12.2019

Не уверен, но если бы следующее было действительно, то да.

++i--

а так нет и выдает ошибку

lvalue required as increment operand

Все поведение унарного оператора можно объяснить только с точки зрения приоритета.

person Anirudh Ramanathan    schedule 18.10.2012
comment
Нет, постфикс имеет более высокий приоритет, чем префикс. - person Seth Carnegie; 18.10.2012