Обладают ли бинарные логические операторы ассоциативностью?
-
27-12-2019 - |
Вопрос
Является a && b && c
определяется языком как означает (a && b) && c
или a && (b && c)
?
Ух ты, Джерри был быстр.Чтобы усилить вопрос:действительно ли это имеет значение?Будет ли заметна разница между a && b && c
интерпретируется как (a && b) && c
или a && (b && c)
?
Решение
§5.14 / 1: «Группы операторов && Оператора слева направо. [...] В отличие от &, && гарантии влево вправо Оценка: Второй операнд не оценивается, если первый операнд ложный. "
Как к тому, когда или как это имеет значение: я не уверен, что это действительно делает для встроенных типов.Это возможно, однако, перегружать его таким образом, чтобы это было бы дело.Например:
#include <iostream>
class A;
class M {
int x;
public:
M(int x) : x(x) {}
M &operator&&(M const &r);
M &operator&&(A const &r);
friend class A;
};
class A {
int x;
public:
A(int x) : x(x) {}
A &operator&&(M const &r);
A &operator&&(A const &r);
operator int() { return x;}
friend class M;
};
M & M::operator&&(M const &r) {
x *= r.x;
return *this;
}
M & M::operator&&(A const &r) {
x *= r.x;
return *this;
}
A &A::operator&&(M const &r) {
x += r.x;
return *this;
}
A &A::operator&&(A const &r) {
x += r.x;
return *this;
}
int main() {
A a(2), b(3);
M c(4);
std::cout << ((a && b) && c) << "\n";
std::cout << (a && (b && c)) << "\n";
}
.
Результат:
9
16
.
Предостережение: это только показывает, как он может быть сделан в вопросе.Я не Особенно рекомендую, чтобы кто-нибудь сделать это, только показывая, что если вы хотите достаточно плохо, вы можете создать ситуацию, в которой это имеет значение.
Другие советы
Тот Самый &&
и ||
короткое замыкание операторов:если операнд слева определяет результат общего выражения, то операнд справа даже не будет вычислен.
Следовательно, математик описал бы их как левоассоциативные, например
a && b && c
⇔ (a && b) && c
, потому что для математика это означает a
и b
рассматриваются в первую очередь.Однако в педагогических целях было бы полезно написать a && (b && c)
вместо этого, чтобы подчеркнуть, что ни то , ни другое b
ни c
будет оценено, если a
это ложь.
Круглые скобки в C изменяют порядок вычисления только тогда, когда они переопределяют приоритет.И то , и другое a && (b && c)
и (a && b) && c
будет оцениваться как a
во-первых, тогда b
, тогда c
.Аналогично, порядок оценки обоих
a + (b + c)
и (a + b) + c
является неуказанным.Контраст a + (b * c)
против (a + b) * c
, где компилятор по - прежнему волен оценивать a
, b
, и c
в любом порядке, но круглые скобки определяют, происходит ли умножение или сложение первым.Также контрастируйте с FORTRAN, где по крайней мере в некоторых случаях выражения, заключенные в скобки, должны быть вычислены первыми.
На самом деле очень важно, чтобы выражение вычисляется слева направо.Это используется для определения короткого замыкания в некоторых выражениях.Вот случай, когда это имеет значение:
vector<vector<int> > a;
if (!a.empty() && !a[0].empty() && a[0].back() == 3)
.
Могу поспорить, вы пишете подобные заявления несколько раз в день.И если ассоциативность не была определена, вы были бы в огромных проблемах.
Если a && b
ложно, то && c
часть никогда не проверяется.Так что да, это имеет значение (по крайней мере, в том смысле, что вам нужно упорядочить операции слева направо). &&
по своей природе является ассоциативной операцией.
Ассоциативное свойство
В рамках выражения, содержащего два или более входов в ряду одного и того же ассоциативного оператора, порядок, в котором выполняются операции, не имеет значения, если последовательность операндов не изменяется.То есть перестройка скобок в таком выражении не изменит его значение.
Поэтому не имеет значения (логически), если вы напишете это как a && (b && c)
или (a && b) && c
.Оба эквивалентны.Но вы не можете изменить порядок операций (например, a && c && b
не эквивалентно a && b && c
).