Какая логическая операция И делает с выводом потока?

Я только что видел код, и я не могу понять, как логично и ведет себя с "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& ссылка, т. е. ссылка на сам поток (полезно для объединения операций вместе). Второй оператор возвращает информацию о том, находится ли поток в состоянии сбоя или нет.

Смотрите следующую документацию для более подробной информации:

Приоритет оператора C++

перегрузка оператора

станд::basic_ostream:: оператор<<;;

std::basic_ios:: оператор bool

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++, и я бы настоятельно не рекомендовал такое использование.

Другие вопросы по тегам