Приоритет оператора, противоречивая документация - PullRequest
0 голосов
/ 15 января 2020

Я освежаю память о приоритетах операторов, потому что я стараюсь быть умным парнем и стараюсь избегать скобок, обновляясь по следующим 2 ссылкам:

cpp ссылка

MS документы

У меня есть одна проблема: эти 2 "надежных" документа не говорят одно и то же, я больше не знаю, кому доверять?

В одном примере Cppreference говорит, что ключевое слово throw находится в той же группе, что и условный оператор. Документы Microsoft говорят, что условный оператор выше throw. Существуют и другие различия.

Какой сайт является правильным, или оба сайта неправильны по-разному?

1 Ответ

2 голосов
/ 15 января 2020

TL; DR: Документы Microsoft можно интерпретировать как менее правильные, в зависимости от того, как вы на них смотрите.

Первое, что вы должны понять, это то, что в языке C ++ нет оператора " Приоритет "правила. C ++ имеет грамматику ; именно грамматика определяет, что означает конкретный фрагмент синтаксиса C ++. Именно грамматика C ++ говорит вам, что 5 + 3 * 4 следует считать эквивалентным 5 + (3 * 4), а не (5 + 3) * 4.

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

Рассмотрим конкретный c пример throw против оператора ?:. На сайте Microsoft говорится, что ?: имеет более высокий приоритет, чем throw, а сайт Cppreference говорит, что они имеют такой же приоритет.

Сначала давайте рассмотрим гипотетическое выражение C ++:

throw val ? one : two

По правилам Microsoft, оператор ?: имеет более высокий приоритет, поэтому будет проанализирован как throw (val ? one : two). По правилам Cppreference оба оператора имеют одинаковый приоритет. Однако, поскольку они имеют ассоциативность справа налево, ?: получает первые метки в подвыражениях. Итак, у нас есть throw (val ? one : two).

Итак, оба они решают один и тот же результат.

Но что говорит грамматика C ++? Хорошо, вот соответствующий фрагмент грамматики:

throw-expression:
  throw  assignment-expression(opt)

assignment-expression:
  conditional-expression
  logical-or-expression assignment-operator initializer-clause
  throw-expression

Это анализируется как выражение броска, которое содержит assignment-expression, которое содержит conditional-expression, которое является где наш ?: лежит. Короче говоря, синтаксический анализатор анализирует его как throw (val ? one : two).

Таким образом, обе страницы одинаковы, и обе они верны.

Теперь рассмотрим:

val ? throw one : two

Как это анализируется? Хорошо, что нужно помнить, что ?: является троичным оператором; в отличие от большинства других, у него есть три условия. То есть сам conditional-expression не является завершенным , указанным до тех пор, пока не будет проанализирован : <something>.

Таким образом, приоритет throw против ?: в данном случае не имеет значения. throw one находится внутри троичного оператора, потому что выражение буквально в пределах троичного оператора. Два оператора не конкурируют.

Наконец, как насчет:

val ? one : throw two

Microsoft дает ?: более высокий приоритет. Согласно документации Microsoft, приоритет «определяет порядок операций в выражениях, которые содержат более одного оператора». Таким образом, ?: происходит первым.

Но вот в чем дело. throw само по себе является грамматически допустимым выражением (оно допустимо только для C ++ в пределах предложения catch, но грамматика везде допустима). Таким образом, val ? one : throw может быть законным выражением, что, как кажется, говорят правила Microsoft.

Конечно, (val ? one : throw) two не является законным выражением, потому что () two не является юридическая грамматика C ++. Таким образом, можно интерпретировать правила Microsoft, чтобы сказать, что это должно быть ошибкой компиляции.

Но это не так. Грамматические состояния C ++:

conditional-expression:
  logical-or-expression
  logical-or-expression ? expression : assignment-expression

throw two - это полный assignment-expression, используемый в качестве третьего операнда данного выражения. Так что это должно быть проанализировано как val ? one : (throw two).

А как насчет Cppreference? Что ж, давая им ассоциативность справа налево, throw two группируется с самим собой. Так что стоит считать val ? one : (throw two).

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