Какая логическая операция И делает с выводом потока?
Я только что видел код, и я не могу понять, как логично и ведет себя с "cout" здесь:
int userInput = 9; // Suppose user input is 9.
int remainder = 9 % 2;
(remainder & 1 && std::cout<<"odd" )|| cout<<"even";
2 ответа
Строка, о которой идет речь:
(remainder & 1 && std::cout<<"odd" ) || cout<<"even";
То же самое, что и в следующих случаях, когда вы учитываете приоритет оператора и перегрузки оператора:
((remainder & 1) && (operator<<(std::cout, "odd").operator bool())) || (operator<<(std::cout, "even").operator bool());
std::cout
(в более общем смысле, std::basic_ostream
) имеет operator<<()
а также operator bool()
операторы определены. Первый оператор возвращает std::basic_ostream&
ссылка, т. е. ссылка на сам поток (полезно для объединения операций вместе). Второй оператор возвращает информацию о том, находится ли поток в состоянии сбоя или нет.
Смотрите следующую документацию для более подробной информации:
std::cout<<"odd"
это выражение, которое вернет std::cout
(вот почему вы можете сделать std::cout << a << b << c
). При оценке в логическом контексте он просто возвращает true, если бит сбоя не установлен. Таким образом, если операция вывода завершится успешно, она будет оценена как истина.
Однако цель этого кода не в том, чтобы проверить это значение, а в умном (и не очень удобочитаемом) способе выражения этого:
if (remainder & 1) {
std::cout << "odd";
} else {
std::cout << "even";
}
Он использует преимущества короткого замыкания &&
а также ||
операторы:
- В
a && b
, еслиa
ложно, то это оценивается какa
(b
не оценивается!) в противном случае оценивается какb
, - В
a || b
, еслиa
верно, то это оценивает какa
(b
не оценивается!) в противном случае оценивается какb
,
Так что если remainder & 1
оценивается как ложное (в данном случае ноль) std::cout << "odd"
не оценивается, потому что &&
выражение короткое замыкание, возвращающее ложь. Это левый операнд к внешнему ||
выражение, которое вызывает его b
(std::cout << "even"
), чтобы быть оцененным, записывая "даже" на выходе.
Если remainder & 1
оценивается как истина (не ноль в данном случае), тогда правый операнд для &&
оценивается, отображая "нечетное". Предполагая, что эта операция выполнена успешно, левый операнд для ||
операция будет истинной, что приводит к ее короткому замыканию и неправильной оценке правильного операнда.
1 Опытные программисты, вероятно, точно знают, что здесь происходит, но, как вы обнаружили, эта техника не самая читаемая. Лучше (IMO) быть прямым в отношении цели кода, поэтому я бы просто использовал if
условно - или, по крайней мере, использовать троичный оператор: std::cout << (remainder & 1 ? "odd" : "even")
,
В других языках (на ум приходит JavaScript) (ab) использование операторов короткого замыкания является очень распространенной техникой. Я обычно не вижу, чтобы они использовали этот способ в C++, и я бы настоятельно не рекомендовал такое использование.