В настоящее время я изучаю C ++ с помощью книги C ++ Primer, и одно из упражнений в книге:
Объясните, что делает следующее выражение:
someValue ? ++x, ++y : --x, --y
Что мы знаем? Мы знаем, что тернарный оператор имеет более высокий приоритет, чем оператор запятой. С бинарными операторами это было довольно легко понять, но с тернарным оператором я немного борюсь. С бинарными операторами «имеющий более высокий приоритет» означает, что мы можем использовать круглые скобки вокруг выражения с более высоким приоритетом, и это не изменит выполнение.
Для тернарного оператора я бы сделал:
(someValue ? ++x, ++y : --x, --y)
эффективно приводя к тому же коду, который не помогает мне понять, как компилятор сгруппирует код.
Однако из тестирования с компилятором C ++ я знаю, что выражение компилируется, и я не знаю, что :
оператор может обозначать сам по себе. Таким образом, компилятор, кажется, правильно интерпретирует тернарный оператор.
Затем я выполнил программу двумя способами:
#include <iostream>
int main()
{
bool someValue = true;
int x = 10, y = 10;
someValue ? ++x, ++y : --x, --y;
std::cout << x << " " << y << std::endl;
return 0;
}
Результаты в:
11 10
А с другой стороны с someValue = false
него печатает:
9 9
Почему компилятор C ++ генерирует код, который для истинной ветви тернарного оператора только увеличивает x
, а для ложной ветви тернарного оператора уменьшает и x
и y
?
Я даже зашел так далеко, что заключил настоящую ветку в круглые скобки:
someValue ? (++x, ++y) : --x, --y;
но это все равно приводит к 11 10
.
источник
?
это условный оператор . Термин тернарный оператор просто означает оператор с тремя операндами. Условный оператор - один из примеров тернарного оператора, но язык может (теоретически) иметь несколько тернарных операторов.Ответы:
Как сказал @Rakete в своем превосходном ответе, это сложно. Я бы хотел добавить к этому немного.
Тернарный оператор должен иметь вид:
Итак, у нас есть следующие сопоставления:
someValue
: логическое-или-выражение++x, ++y
: выражение--x, --y
или только--x
?Фактически это происходит только
--x
потому, что выражение присваивания не может быть проанализировано как два выражения, разделенных запятой (в соответствии с правилами грамматики C ++), поэтому--x, --y
его нельзя рассматривать как выражение присваивания .В результате часть тернарного (условного) выражения будет выглядеть так:
Для удобства чтения
++x,++y
может быть полезно рассматривать вычисление как если бы оно было заключено в круглые скобки(++x,++y)
; все, что содержится между?
и,:
будет упорядочено после условного. (Я заключу их в скобки в оставшейся части сообщения).и оценивается в таком порядке:
someValue?
(++x,++y)
или--x
(в зависимости отbool
результата 1.)Это выражение затем обрабатывается как левое подвыражение оператора запятой, а правое подвыражение имеет
--y
следующий вид:Это означает, что левая сторона является выражением отброшенного значения , что означает, что она определенно оценивается, но затем мы оцениваем правую часть и возвращаем ее.
Так что же происходит, когда
someValue
естьtrue
?(someValue?(++x,++y):--x)
выполняет и увеличиваетx
иy
быть11
и11
--y
который затем уменьшаетсяy
обратно до10
Чтобы «исправить» поведение, вы можете сгруппировать его в
--x, --y
круглые скобки, чтобы преобразовать его в основное выражение, которое является допустимой записью для выражения присваивания *:* Это довольно забавная длинная цепочка, которая соединяет выражение- присваивание с первичным выражением:
выражение-присваивание --- (может состоять из) -> условное-выражение -> логическое-или-выражение -> логическое-и-выражение -> включающее-или-выражение -> исключающее-или-выражение - -> и-выражение -> выражение-равенство -> выражение-отношения -> выражение-сдвиг -> аддитивное-выражение -> мультипликативное-выражение -> выражение-pm -> выражение-приведение -> унарное-выражение -> постфиксное-выражение -> первичное-выражение
источник
{ ... }
их можно рассматривать как выражение), у меня теперь есть ответ => это для того, чтобы избежать необходимости вводить оператор запятой, который ведет себя таким хитрым образом.assignment-expression
цепочке?Вау, это сложно.
Компилятор видит ваше выражение как:
Тернарному оператору нужен a
:
, он не может стоять сам по себе в этом контексте, но после него нет причин, по которым запятая должна принадлежать ложному регистру.Теперь может быть понятнее, почему вы получили такой результат. Если
someValue
это правда, то++x
,++y
и--y
получить казнены, который не эффективно изменить ,y
но прибавляет кx
.Если
someValue
ложно, то--x
и--y
выполняются с уменьшением их обоих на единицу.источник
Вы неверно истолковали то, что произошло. Истинная ветвь увеличивает как
x
иy
. Однакоy
сразу после этого уменьшается безоговорочно.Вот как это происходит: поскольку условный оператор имеет более высокий приоритет, чем оператор запятой в C ++ , компилятор анализирует выражение следующим образом:
Обратите внимание на «осиротевшие»
--y
после запятой. Это то, что приводит к уменьшениюy
, которое было изначально увеличено.Вы были на правильном пути, но заключили в скобки неправильную ветвь: вы можете исправить это, заключив в скобки ветку else, например:
Демо (отпечатки 11 11)
источник
Ваша проблема в том, что тернарное выражение действительно не имеет более высокого приоритета, чем запятая. Фактически, C ++ не может быть точно описан простым приоритетом - и это именно взаимодействие между тернарным оператором и запятой, где оно нарушается.
рассматривается как:
(запятая ведет себя так, как будто она имеет более высокий приоритет). С другой стороны,
рассматривается как:
а тернарный оператор имеет более высокий приоритет.
источник
В ответах упускается из виду (хотя и упоминается в комментариях) то, что условный оператор неизменно используется (преднамеренно?) В реальном коде как ярлык для присвоения одного из двух значений переменной.
Итак, более широкий контекст:
Что на первый взгляд абсурдно, поэтому преступления многообразны:
источник
if
(например, выражение приращения в цикле for). Чем больше контекста может также бытьfor (x = 0, y=0; x+y < 100; someValue?(++x, ++y) :( --x, --y))
с петлей , которая может изменитьx
иy
независимо друг от друга.