Как работает Comma Operator

Как работает оператор запятой на С++?

Например, если:

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;

Ответ 1

Он будет равен b.

Оператор запятой имеет более низкий приоритет, чем назначение.

Ответ 2

Позаботьтесь о том, что оператор запятой может быть перегружен в С++. Фактическое поведение может, таким образом, сильно отличаться от ожидаемого.

В качестве примера Boost.Spirit использует оператор запятой довольно умно, чтобы реализовать инициализаторы списка для таблиц символов. Таким образом, он делает возможным следующий синтаксис:

keywords = "and", "or", "not", "xor";

Обратите внимание, что из-за приоритета оператора код (намеренно!) идентичен

(((keywords = "and"), "or"), "not"), "xor";

То есть первый оператор называется keywords.operator =("and"), который возвращает прокси-объект, на который вызывается оставшийся operator,:

keywords.operator =("and").operator ,("or").operator ,("not").operator ,("xor");

Ответ 3

Оператор запятой имеет приоритет самый низкий всех операторов C/С++. Поэтому всегда он привязывается к выражению, что означает следующее:

a = b, c;

эквивалентно:

(a = b), c;

Еще один интересный факт заключается в том, что оператор запятой вводит точку . Это означает, что выражение:

a+b, c(), d

гарантировано, что его три подвыражения (a + b, c() и d) оцениваются по порядку. Это важно, если у них есть побочные эффекты. Обычно компиляторам разрешено оценивать подвыражения в любом порядке, который они считают нужным; например, при вызове функции:

someFunc(arg1, arg2, arg3)
аргументы

могут быть оценены в произвольном порядке. Обратите внимание, что запятые в вызове функции не являются операторами; они являются разделителями.

Ответ 4

Оператор запятой:

  • имеет самый низкий приоритет
  • лево-ассоциативный

Стандартная версия оператора запятой определяется для всех типов (встроенных и настраиваемых), и она работает следующим образом: exprA , exprB:

  • exprA оценивается
  • результат exprA игнорируется
  • exprB оценивается
  • результат exprB возвращается как результат всего выражения

Для большинства операторов компилятору разрешено выбирать порядок выполнения, и даже требуется пропустить выполнение вообще, если оно не влияет на конечный результат (например, false && foo() пропустит вызов до foo). Однако это не относится к оператору запятой, и указанные шаги всегда будут выполняться *.

На практике оператор запятой по умолчанию работает почти так же, как точка с запятой. Разница заключается в том, что два выражения, разделенные точкой с запятой, образуют два отдельных оператора, а разделение запятой сохраняет все как одно выражение. Вот почему оператор запятой иногда используется в следующих сценариях:

  • Для синтаксиса
  • C требуется одно выражение, а не оператор. например в if( HERE ) Для синтаксиса
  • C требуется один оператор, не более, например. в инициализации цикла for for ( HERE ; ; )
  • Если вы хотите пропустить фигурные скобки и сохранить один оператор: if (foo) HERE ; (пожалуйста, не делайте этого, это действительно уродливо!)

Если оператор не является выражением, точка с запятой не может быть заменена запятой. Например, они запрещены:

  • (foo, if (foo) bar) (if не является выражением)
  • int x, int y (объявление переменной не является выражением)

В вашем случае мы имеем:

  • 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

Ответ 5

Значение a будет b, но значение выражения будет c. То есть, в

d = (a = b, c);

a будет равно b, а d будет равно c.

Ответ 6

Значение

b будет присвоено значению a. Ничего не произойдет с c

Ответ 7

Значение a будет равно b, поскольку оператор запятой имеет более низкий приоритет, чем оператор присваивания.

Ответ 8

Да Оператор Comma имеет низкий приоритет, чем оператор присваивания

#include<stdio.h>
int main()
{
          int i;
          i = (1,2,3);
          printf("i:%d\n",i);
          return 0;
}

Выход: я = 3
Потому что оператор запятой всегда возвращает самое правое значение.
В случае оператора запятой с Оператором присваивания:

 int main()
{
      int i;
      i = 1,2,3;
      printf("i:%d\n",i);
      return 0;
}

Выход: я = 1
Поскольку мы знаем, что оператор с запятой имеет более низкий приоритет, чем назначение.....

Ответ 9

Первые вещи: Запятая на самом деле не является оператором, поскольку компилятор - это просто токен, который получает смысл в контексте с другими токенами.

Что это значит и зачем беспокоиться?

Пример 1:

Чтобы понять разницу между значением одного и того же токена в другом контексте, мы рассмотрим этот пример:

class Example {
   Foo<int, char*> ContentA;
}

Обычно начинающий С++ думал, что это выражение могло бы/могло бы сравнивать вещи, но оно абсолютно неверно, смысл токенов <, > и , зависит от контекста использования.

Правильная интерпретация приведенного выше примера, конечно же, является установлением шаблона.

Пример 2:

Когда мы пишем типичный цикл цикла с более чем одной переменной инициализации и/или более чем одним выражением, которое должно быть сделано после каждой итерации цикла, мы также используем запятую:

for(a=5,b=0;a<42;a++,b--)
   ...

Значение запятой зависит от контекста использования, здесь это контекст конструкции for.

Что означает запятая в контексте?

Чтобы усложнить его еще больше (как всегда в С++), оператор запятой может быть перегружен (благодаря Konrad Rudolph, указав это).

Чтобы вернуться к вопросу, Код

a = b, c;

означает для компилятора что-то вроде

(a = b), c;

поскольку приоритет токена/оператора = выше приоритета маркера ,.

и это интерпретируется в контексте типа

a = b;
c;

(обратите внимание, что интерпретация зависит от контекста, здесь она не является вызовом функции/метода или статированием шаблона.)