Если Вы видите этот код,
class A{
public:
A(int a):var(a){}
int var;
};
int f(A obj) {
return obj.var;
}
int main() {
//std::cout<<f(23); // output: 23
std::cout<<f(23, 23); // error: too many arguments to function 'int f(A)'
return 0;
}
f(23, 23)
не компилирует, потому что запятая действует как разделитель здесь и не как оператор запятой.
Где все разве запятая не работает оператором запятой? Или наоборот?
С грамматической точки зрения параметры вызова функции образуют необязательное выражение-список внутри круглых скобок. Список expression-list состоит из одного или нескольких assignment-expression, разделенных маркером запятой. Запятая может означать оператор запятой только там, где ожидается выражение.
Оператор запятой делает выражение из выражения, ,
и присваивания-выражения, но выражение, включающее оператор запятой, само по себе не является выражением присваивания, поэтому не может появиться в списке выражений, за исключением случаев, когда оно является составной частью чего-то, что является выражением присваивания.
Например, вы можете окружить любое выражение (включая выражение с использованием оператора запятой) скобками, чтобы получить primary-expression, которое является assignment-expression и, следовательно, допустимо в expression-list.
Например,
постфикс-выражение, где выражение-список состоит из двух выражений-присвоений, каждое из которых является идентификатором.
f( a, b );
постфикс-выражение, где выражение-список состоит из одного назначения-выражения, которое является первичным-выражением, которое является выражением в скобках выражением с использованием оператора запятой.
f( (a, b) );
Я просмотрел черновой вариант Стандарта. По сути, в грамматике продукция -списка
- это те, в которых есть запятые для разделения различных элементов. Следующие результаты относятся к C ++ 03. В C ++ 0x список-выражений напрямую делегирует список-инициализаторов , потому что в C ++ 0x списки фигурных скобок могут также встречаться в аргументах функций и конструкторов.
инициализатор-декларатор -list Различные имена, объявленные в одном объявлении
Пример:
int a, b;
список-деклараторов-членов Аналогично списку деклараторов инициализации, но для объявлений членов в классах.
Пример:
struct A {int a, b; };
mem-initializer-list Список инициализаторов для членов
Пример:
struct A {A (): a (0), b (0) {} int a; int b; };
type-id-list Список типов для спецификаций исключений
Пример:
void f () throw (int, bool) {}
Существует список идентификаторов для параметров макроса, которого у меня нет в этом списке, потому что это действительно часть грамматики препроцессора.
Это связано с определением языка выражений, которое является довольно сложным.
f(1, 2)
- это выражение вызова функции с двумя параметрами. И наоборот, f((1, 2))
- это выражение вызова функции с одним параметром, которым является подвыражение 1, 2
, которое оценивается в 2.
Использование запятой в качестве символа оператор отличается от его использования в вызовы функций и определения, объявления переменных, перечисление объявления и подобные конструкции, где он действует как разделитель.
Оператор запятой всегда действует как оператор запятой, но запятая не всегда означает оператор запятой - иногда это просто знак препинания.
Что касается знаков препинания, то простой ответ - «когда так сказано в стандарте». Прохождение всех ситуаций, в которых так сказано в стандарте, дает гораздо более длинный ответ, но тот, который вряд ли будет намного более полезным, потому что (например) он должен иметь дело с рядом угловых случаев, которым большинство людей не заботится о.