Почему преобразование std::optional<int> в std::optional<bool> меняет хранимое значение?

Рейтинг: 0Ответов: 1Опубликовано: 22.01.2023
#include <iostream>
#include <optional>

int main() {
    const auto a = std::optional<int>(0);
    const auto b = std::optional<bool>(a);

    std::cout << a.value() << b.value() << '\n';
}

Почему программа печатает 01, а не 00?

Ответы

▲ 2Принят

Потому что при таком преобразовании происходит неявное преобразование std::optional<int>(0) в bool. А в документации ясно говорится, что такое преобразование дает true, если в std::optional хранится значение, и false, если его нет. Но ведь в std::optional<int>(0) значение хранится, с этим вы не спорите? Вот и получается, что его приведение к bool дает значение true, все в соответствии со стандартом...

Если хотите получить значение, то делайте уж

const auto b = std::optional<bool>(*a);

только при использовании оператора * обратите внимание на примечание

This operator does not check whether the optional contains a value! You can do so manually by using has_value() or simply operator bool(). Alternatively, if checked access is needed, value() or value_or() may be used.

P.S. Мне показалось правильным внести в ответ из комментариев следующее:

Если в первом заменить тип int на bool, то будет ожидаемый вывод. Если поставить в первом int, а во втором double, то тоже будет ожидаемый результат, хотя при этом типы разные.

Потому что нет оператора преобразования optional<int> в double, только в bool. Соответственно, рассматриваются варианты, требующие более сложного преобразования.
<bool> -> <bool> - работает точно соответствующий конструктор копирования.
<int> -> <bool> - работает приведение типа к bool, о котором я уже написал.
<int> -> <double> — ничего проще, чем шаблонный конструктор, нет, применяется он.