Как работает оператор запятой в C ++?
Например, если я делаю:
a = b, c;
В конечном итоге равен b или c?
(Да, я знаю, что это легко проверить - просто документируйте здесь, чтобы кто-то быстро нашел ответ.)
Обновление: этот вопрос выявил нюанс при использовании оператора запятой. Просто документировать это:
a = b, c; // a is set to the value of b!
a = (b, c); // a is set to the value of c!
Этот вопрос был фактически вдохновлен опечаткой в коде. Что должно было быть
a = b;
c = d;
Превратился в
a = b, // <- Note comma typo!
c = d;
c++
comma-operator
Джо Шнайдер
источник
источник
a = (b, c);
.a = b, c = d;
самом деле работает так же, как предполагалосьa = b; c = d;
?b
иd
являются оценками функций, которые используют (и изменяют) общее состояние, порядок выполнения не определяется доC++17
.Ответы:
Это было бы равно
b
.Оператор запятой имеет более низкий приоритет, чем присваивание.
источник
Обратите внимание, что оператор запятой может быть перегружен в C ++. Таким образом, фактическое поведение может сильно отличаться от ожидаемого.
Например, Boost.Spirit довольно умно использует оператор запятой для реализации инициализаторов списка для таблиц символов. Таким образом, это делает возможным и значимым следующий синтаксис:
Обратите внимание, что из-за приоритета оператора код (намеренно!) Идентичен
То есть первый вызванный оператор
keywords.operator =("and")
возвращает прокси-объект, для которогоoperator,
вызываются остальные s:источник
char[]
, который не может быть перегружен. Код намеренно сначала вызывает,operator=
а затем последовательноoperator,
для каждого оставшегося элемента.Оператор запятой имеет самый низкий приоритет среди всех операторов C / C ++. Следовательно, это всегда последнее, связываемое с выражением, означающее следующее:
эквивалентно:
Еще один интересный факт заключается в том, что оператор запятой вводит точку последовательности . Это означает, что выражение:
гарантируется, что его три подвыражения ( a + b , c () и d ) будут оцениваться по порядку. Это важно, если у них есть побочные эффекты. Обычно компиляторам разрешается оценивать подвыражения в любом порядке, который они сочтут нужным; например, в вызове функции:
аргументы могут быть оценены в произвольном порядке. Обратите внимание, что запятые в вызове функции не являются операторами; они являются разделителями.
источник
,
него такой низкий приоритет, он даже отстает от самого себя ;) ... То есть: оператор запятой имеет более низкий приоритет, чем разделитель запятой . Итак, если вы хотите использовать оператор запятая в качестве одного аргумента функции, присваивания переменной или другого списка, разделенного запятыми, - вам нужно использовать круглые скобки, например:int a = 1, b = 2, weirdVariable = (++a, b), d = 4;
Оператор запятой:
Версия оператора запятой по умолчанию определена для всех типов (встроенных и пользовательских) и работает следующим образом
exprA , exprB
:exprA
оцениваетсяexprA
игнорируетсяexprB
оцениваетсяexprB
возвращается как результат всего выраженияВ большинстве операторов компилятору разрешается выбирать порядок выполнения, и даже требуется вообще пропустить выполнение, если это не повлияет на конечный результат (например
false && foo()
, пропустит вызовfoo
). Однако это не относится к оператору запятой, и вышеописанные шаги всегда будут выполняться * .На практике оператор запятой по умолчанию работает почти так же, как точка с запятой. Разница в том, что два выражения, разделенные точкой с запятой, образуют два отдельных оператора, а разделение запятыми сохраняет все как одно выражение. Вот почему оператор запятой иногда используется в следующих сценариях:
if( HERE )
for
циклаfor ( HERE ; ; )
if (foo) HERE ;
(пожалуйста, не делайте этого, это действительно ужасно!)Если оператор не является выражением, точку с запятой нельзя заменить запятой. Например, они запрещены:
(foo, if (foo) bar)
(if
это не выражение)В вашем случае мы имеем:
a=b, c;
, эквивалентноa=b; c;
, предполагая, чтоa
это тип, который не перегружает оператор запятой.a = b, c = d;
эквивалентноa=b; c=d;
, если предположить, чтоa
это тип, который не перегружает оператор запятой.Обратите внимание, что не каждая запятая на самом деле является оператором запятой. Некоторые запятые, которые имеют совершенно другое значение:
int a, b;
--- список объявления переменных разделен запятыми, но это не операторы запятыхint a=5, b=3;
--- это также список объявлений переменных через запятуюfoo(x,y)
--- список аргументов через запятую. На самом делеx
иy
можно оценить в любом порядке!FOO(x,y)
--- разделенный запятыми список аргументов макросаfoo<a,b>
--- список аргументов шаблона через запятуюint foo(int a, int b)
--- список параметров через запятуюFoo::Foo() : a(5), b(3) {}
--- разделенный запятыми список инициализатора в конструкторе класса* Это не совсем так, если вы применяете оптимизацию. Если компилятор распознает, что определенный фрагмент кода не оказывает абсолютно никакого влияния на остальные, он удалит ненужные операторы.
Дальнейшее чтение: http://en.wikipedia.org/wiki/Comma_operator
источник
operator ,
перегрузке вы теряете гарантии на ассоциативность (так же, как вы теряете свойства короткого замыканияoperator&&
иoperator||
если они перегружены)?a, b, c
всегда означает(a, b), c
и никогдаa, (b, c)
. Последняя интерпретация может даже привести к ошибке компиляции, если элементы имеют разные типы. Что вы можете сделать после того, как порядок вычислений аргументов? Я не уверен в этом, но, возможно, вы правы: может случиться так, чтоc
оценивается раньше,(a, b)
даже если запятая является ассоциативной слева.struct Foo { Foo() : a(5), b(3) {} int b; int a; }
evaulatesb(3)
перед темa(5)
. Это важно , если ваш список следующим образом:Foo() : a(5), b(a) {}
. b не будет установлен на 5, а скорее на неинициализированное значение a, о котором ваш компилятор может или не может предупреждать.Значение
a
будетb
, но значение выражения будетc
. То есть ва будет равно
b
иd
будет равноc
.источник
a = b; d = c;
?Значение b будет присвоено a. Ничего не случится с
источник
Значение a будет равно b, так как оператор запятой имеет более низкий приоритет, чем оператор присваивания.
источник
Да Оператор запятой имеет меньший приоритет, чем оператор присваивания
Выход: i = 3,
потому что оператор запятой всегда возвращает самое правое значение.
В случае оператора запятой с оператором присваивания:
Ouput: i = 1
Как мы знаем, оператор запятой имеет более низкий приоритет, чем присваивание .....
источник
i = 1;
в этой строке?Перво-наперво: запятая на самом деле не является оператором, для компилятора это просто токен, который получает значение в контексте с другими токенами.
Что это значит и зачем?
Пример 1:
Чтобы понять разницу между значением одного и того же токена в другом контексте, рассмотрим следующий пример:
Обычно начинающие C ++ были бы думать , что это выражение может / будет сравнивать вещи , но это не так Absolutly, смысл
<
,>
и,
маркеры на зависим контексте использования.Правильная интерпретация приведенного выше примера состоит в том, что он является шаблоном.
Пример 2:
Когда мы пишем типичный цикл for с несколькими переменными инициализации и / или несколькими выражениями, которые следует выполнять после каждой итерации цикла, мы также используем запятую:
Значение запятой зависит от контекста использования, здесь это контекст
for
конструкции.Что на самом деле означает запятая в контексте?
Чтобы еще больше усложнить (как всегда в C ++), оператор запятой сам может быть перегружен (спасибо Конраду Рудольфу за указание на это).
Чтобы вернуться к вопросу, Кодекс
значит для компилятора что-то вроде
потому что приоритет от
=
маркеров / оператора выше , чем приоритет из,
маркеров.и это интерпретируется в контексте, как
(обратите внимание, что интерпретация зависит от контекста, здесь она не является ни вызовом функции / метода, ни созданием шаблона.)
источник