После некоторого времени отладки я почувствовал себя глупо, обнаружив глупость в моем коде, которая сводится к чему-то вроде этого:
int main()
{
double p1[] = { 1, 2, 3 };
double p2[] = { 1, 2, 3 };
int color = 1;
bool some_condition = true;
if (some_condition) (p1, p2, color);
}
(p1, p2, color)
выражение вычисляется до своего последнего операнда, но должен ли компилятор защищать меня каким-то образом? (Visual Studio ничего не сказала)
И да, вы догадались, я хотел вызвать функцию рисования: Draw(p1, p2, color)
В C ++ выражение (p1, p2, color)
заставляет компилятор интерпретировать запятые в скобках как оператор последовательной оценки.
Оператор последовательной оценки является бинарным оператором, который оценивает свой первый операнд как void
и отбрасывает результат, затем он оценивает второй операнд и возвращает его значение и тип. Поэтому выражение (p1, p2, color)
будет оцениваться следующим образом:
p1
оценивается и отбрасывается, затем (p2, color)
оценивается и результат (p2, color)
возвращаетсяp2
оценивается и отбрасывается, затем color
оценивается и результат color
возвращаетсяТаким образом, утверждение:
if (some_condition) (p1, p2, color);
Эквивалентно:
if (some_condition) color;
Некоторые компиляторы могут выдавать предупреждение, потому что во время оценки выражения (p1, p2, color)
оценки p1
а также p2
приведет к неиспользованию:
CLANG LIVE DEMO
GCC LIVE DEMO
(Как вы уже упоминали Visual Studio не будет предупреждать вообще.)
Помимо этих предупреждений, код является легитимным C ++ (то есть синтаксис C ++ не нарушается).
Вопрос о том, должен ли компилятор защищать вас, спорен. По моему скромному мнению, это должно вас защитить, так как такие выражения, хотя и правильные с точки зрения синтаксиса C ++, могут привести к очень трудным для обнаружения ошибкам (например, в случае сбоя внутри if
выражение).
Это совершенно правильный код, поэтому компилятору не нужно выдавать диагностику, хотя в этом случае полезно иметь диагностику. Это одна из причин, по которой многие разработчики предпочитают clang
так как они имеют тенденцию идти выше того, что требуется, когда дело доходит до диагностики.
С правилами стандартов диагностических сообщений мы можем обратиться к проект стандарта C ++ раздел 1.4
Соответствие реализации который говорит (акцент мой):
Набор диагностируемые правила состоят из всех синтаксических и семантических
правила в этом международном стандарте, за исключением тех правил, содержащих
явное обозначение, что «диагностика не требуется» или которые
описывается как результат «неопределенного поведения».Хотя этот международный стандарт устанавливает только требования к C ++
реализации, эти требования часто легче понять, если
они сформулированы как требования к программам, частям программ или
выполнение программ. Такие требования имеют следующее значение:
Если программа не содержит нарушений правил в этом международном стандарте, соответствующая реализация
в пределах своих ресурсов принять и правильно выполнить2 эта программа.Если программа содержит нарушение любого диагностируемого правила или вхождение конструкции, описанной в
этот стандарт как «условно поддерживаемый», когда реализация не поддерживает эту конструкцию,
соответствующая реализация выдает хотя бы одно диагностическое сообщение.Если программа содержит нарушение правила, для которого не требуется диагностика, настоящий международный стандарт не устанавливает требований в отношении реализации этой программы.
Эта программа не нарушает синтаксические или семантические правила, поэтому диагностика не требуется.
У нас есть следующий код:
if (some_condition) (p1, p2, color);
^ ^ ^
1 2 3
1
является Выражение-заявление который действителен в этом контексте для и если заявление. Мы можем увидеть это, перейдя к грамматике:
if ( condition ) statement
а также:
statement:
attribute-specifier-seqopt expression-statement
а также:
expression-statement:
expressionopt;
а также:
primary-expression:
( expression )
И то и другое 2
а также 3
являются оператор запятой который оценит левый операнд и отбросит значение, а затем снова вычислит правый операнд, ничего недопустимого здесь.
Так что же раздел 5.18
Оператор запятой говорит:
Пара выражений, разделенных запятой, оценивается слева направо;
левое выражение является выражением отброшенного значения (раздел 5).83
и выражение отброшенного значения покрыто в разделе 5
который говорит:
В некоторых контекстах выражение появляется только для его побочных эффектов.
Такое выражение называется выражением отброшенного значения.
Так как значение результата левого выражения отбрасывается, мы должны заботиться только о побочный эффект. В вашем конкретном случае оценка переменной не имеет другого эффекта, кроме генерации значения, отсюда и предупреждения, но если вы использовали функцию вместо нее, например:
bool func()
{
//...
}
и измените свой код на:
if (some_condition) (func(), func(), func() );
ни clang
ни gcc
будет предоставлять предупреждение, так как предположительно func
будет выполнять некоторые бок-ДЕЙСТВИТЕЛЬНО что тебя волнует