среда, 11 ноября 2026 г.

[prog.c++.thoughts] Тип bool временами не так полезен, как кажется

Заголовок поста может звучать провокационно, но когда я задумываюсь о местах, в которых bool уместен, так их оказывается всего ничего:

  • тип возвращаемого значения для методов empty в контейнерах;
  • тип возвращаемого значения для метода has_value в optional;
  • оператор приведения к bool в умных указателях, чтобы можно было писать if(my_ptr) (+ сюда же аналогичный оператор в optional);
  • иногда результаты проверок с бинарным результатом "да"/"нет", которые (результаты в смысле) нужно зачем-то сохранить.

Вот, пожалуй, и все. Остальное полезное, скорее всего, будет всего лишь вариациями на вышеозвученные темы.

Если bool используется в качестве типов параметров для функций, то в коде получаются ужасы вроде:

remove_relations(obsolete_relations, false, false, &errors);
delete_nodes(obsolete_nodes, false, &errors);
add_nodes(new_nodes, true, false, &errors);
add_nodes(changed_nodes, false, false, &errors);
add_relations(new_relations, false, true, &errors);

Что здесь означает каждый true и false, почему они именно такие -- хз, удачи в разборах.

Если bool используется в качестве возвращаемого значения, то получается не менее удручающе:

auto item_processor = [&](item_id id, bool pos_already_provided = false){
    auto res = calculate_one_value(
            id, weights, weights_params, global_pos,
            pos_already_provided);

    if (res.m_should_obtain_pos) {
        need_deep_search = true;

        sum = 0;
        return false;
    }

    if (!res.m_continuation_operator_found) {
        value = res.m_value;
        return false;
    }

    if (res.m_value)
        sum += data_extractor::get_number(res.m_value);
           
    return true;
};

Вот честно, пара-тройка таких функций, и мозги начинают плавиться.

Поэтому для себя сделал вывод:

  • bool в качестве типа аргумента функции/метода -- ни в коем случае. Лучше такого вообще не делать, вместо bool должен использоваться enum class;
  • bool в качестве возвращаемого значения -- если для случаев empty/has_value, то OK, в остальных случаях лучше enum class. Во многом уместность bool определяется именем и назначением функции/метода. Если это getter с именами вроде has_something или is_something, или can_do_something, или must_do_something (т.е. в названии сформулирован вопрос, ответом на который может быть только "да" или "нет"), то норм. Но если если метод мутирующий или функция имеет побочные эффекты, а возвращается bool, то тут могут (и скорее всего будут) возникать вопросы при чтении кода с использованием таких методов/функций;
  • bool в качестве локальной переменной -- сомнительно, но OK, особенно если это константа. Если не константа, то таки лучше подумать в сторону enum class;
  • bool в качестве члена класса -- сомнительно, но в некоторых случаях может быть OK. Например, если это флаг has_value в optional (или что-то вроде этого).

Вполне себе подходящий случай для bool в качестве члена класса -- это статическая константа value в метафункции, вроде:

struct some_trait {
  static constexpr bool value = ...;
};

Если же говорить в целом, то сам по себе тип bool должен быть в языке. И еще лучше, если он никак не смешивается с другими типами и не может приводиться в другие типы (или автоматически выводиться из других типов). Потому что если bool нет и начинаются извращения с int-ами и вручную написанными константами TRUE и FALSE, то это еще хуже (сам через это проходил 30 лет назад). Но таки мест, где bool был бы предпочтительнее специально написанного enum class-а, на сегодня, не так много, как кажется.

PS. Самым же бесполезным типом в C++, наверное, является тип short.

Комментариев нет: