Гарантируется ли, что поразрядное «и» для bool не закорачивается?

Недавно я наткнулся на фрагмент кода, который выглядел так:

bool MyClass::do_work()
{
    bool success = true;
    for (auto const& worker : m_workers)
    {
        success &= worker.do_work();  // worker.do_work() returns a bool
    }
    return success;
}

Если я правильно понимаю, функция возвращает true, если все рабочие возвращают true, и возвращает false, если какой-либо рабочий возвращает ложь. Однако он всегда оценивает всех рабочих (что желательно). Оценка короткого замыкания не выполняется, поскольку использовался побитовый оператор &=, а не логический оператор &&.

Гарантировано ли такое поведение? Точнее, гарантируется ли, что побитовый & всегда оценивает оба операнда, даже если они имеют тип bool? Я встречал много ответов SO относительно гарантированной оценки короткого замыкания для &&, но ни один из них не утверждает, что для & существует гарантированная оценка без короткого замыкания.

Если такое поведение гарантировано, это хороший стиль программирования? Мне потребовалось больше, чем беглый взгляд, чтобы понять функцию, потому что я раньше не видел этого стиля, и сначала я был сбит с толку, была ли задействована оценка короткого замыкания или нет.

Есть ли лучшая альтернатива, чем следующая?

bool MyClass::do_work()
{
    bool success = true;
    for (auto const& worker : m_workers)
    {
        if (!worker.do_work())
        {
            success = false;
        }
    }
    return success;
}

Я бы сказал, что это очень запутанный стиль: кажется, что легко упустить из виду эффект отсутствия короткого замыкания.

user3458 08.01.2019 15:06

Обычно оцениваются все операнды оператора, за исключением операторов &&, || и ?:. Стандарт даже упоминает для &&, что «В отличие от &, && гарантирует оценку слева направо: второй операнд не оценивается, если первым операндом является false».. Что касается хорошего стиля программирования, то это основано на мнении.

Holt 08.01.2019 16:03

@ Вы, я не думаю, что стандарт гарантирует, что all_of не производит короткого замыкания, это было бы действительно странно.

Holt 08.01.2019 16:39

@Holt Как all_of связан с поразрядным &?

pschill 08.01.2019 16:41

@Holt: Я понял это ок. Через 3 секунды после публикации :)

You 08.01.2019 16:41

@pschill Я отвечал на теперь удаленный комментарий от Ты;)

Holt 08.01.2019 16:43

"Есть ли лучшая альтернатива [...]?" Немного возразил бы, да (?): std::count_if (m_workers.begin(), m_workers.end(), [](const auto& worker) { return !worker.do_work(); }) == 0;

You 08.01.2019 16:48

Или success = worker.do_work() && success;, если вы хотите придерживаться императивного цикла.

Pete Kirkham 08.01.2019 17:06
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
8
98
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Если это явно не указано в стандарте, все операнды оператора оцениваются и распределяются по порядку. 1 в C++:

[intro.execution]

Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced. [...] The value computations of the operands of an operator are sequenced before the value computation of the result of the operator. [...]

Единственные три исключения, которые приходят мне в голову, - это операторы 2&&, || и ?:.

Стандарт даже упоминает для &&3, что:

[expr.log.and]

Unlike &, && guarantees left-to-right evaluation: the second operand is not evaluated if the first operand is false.

Что касается хорошего стиля программирования, то это основано на мнении.


1 Unsequenced basically means that if you have A @ B (where @ is an operator), B (and its side effects) can be evaluated before A, which is why construct such as i++ + ++i are undefined behavior.

2 Note that for overloaded && and || operator, this is not true anymore since both operands are evaluated. ?: cannot be overloaded.

3 There is a similar note for | within [expr.log.or].

В отличие от &, && гарантирует оценку слева направо: второй операнд не оценивается, если первым операндом является false.. Позвольте мне перефразировать это: & не гарантирует оценку слева направо. К сожалению, это утверждение означает, что оператор & может выполнить оценку короткого замыкания, это просто не гарантируется.
pschill 08.01.2019 16:43

@pschill Нет, это означает, что & может оценивать правый операнд перед левым, как и большинство операторов. Когда вы выполняете A op B, B можно оценить до A, но будут оцениваться оба, за исключением &&, || и ?:.

Holt 08.01.2019 16:45

@pschill Версия || немного лучше, если вы предпочитаете: «В отличие от |, || гарантирует оценку слева направо; Кроме того, второй операнд не оценивается, если первый операнд оценивается как истина».

Holt 08.01.2019 16:46

@pschill Я отредактировал свой ответ, чтобы добавить стандартную цитату относительно поведения операторов по умолчанию, в которой говорится, что все операнды оператора оцениваются, если не указано иное.

Holt 08.01.2019 16:59

Итак, дело в том, что операторы (кроме && и т. д.) Оцениваются как «обычные» функции C++, что означает, что оцениваются все аргументы. Спасибо :)

pschill 09.01.2019 08:49

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