#новичкам
Если у вас есть С++17, то поздравляю, у вас есть std::variant, который решает проблему суперпозиции полей из прошлого поста.
По сути, std::variant - это типобезопасный юнион, который хранит только один тип из списка шаблонных параметров. Объект варианта можно проверить на наличие нужного типа и есть способы no-exceptions сообщения об ошибке, если вы хотите получить доступ не к тому типу. Обычный std::get кидает исключение при неправильном доступе, но std::holds_alternative или std::get_if предоставляют небросающий апи:
struct Error {
std::string message;
};
std::variant<double, Error> safe_divide(double a, double b) {
if (b == 0.0) {
return Error{std::string{"Division by zero"}};
}
return a / b;
}
auto div_result = safe_divide(10.0, 2.0);
if (std::holds_alternative<double>(div_result)) {
std::cout << "Result: " << std::get<double>(div_result) << std::endl;
} else {
std::cout << "Error: " << std::get<Error>(div_result).message << std::endl;
}Библиотечный код стал ощутимо короче и не перестал быть таким же читаемым. Но вот клиентский код стал очевидно менее читаемым, по сравнению с предыдущим постом.
К этому привело то, что семантика "результат или ошибка" не заложена в самой идее std::variant. Для него все типы изначально равнозначны и равноожидаемы. Нет плохого и хорошего типа.
Чисто технически, вы можете сделать простую обертку из варианта, чтобы такая семантика появилась, но оставим это в качестве домашнего задания читателям.
Вариант не требует динамических аллокаций и занимает столько памяти, сколько нужно для самого большого типа(помимо небольшой метаинформации). Так что по части эффективности здесь все хорошо.
Еще можно легко возвращать фиксированный набор из нескольких типов ошибки или значений, просто добавив нужный тип в список шаблонных параметров.
В небросающем коде нужно обязательно проверять каждый доступ к объекту варианта, потому что std::get кидает исключение(вообще говоря, в любом коде). Ну или сразу используйте std::get_if, если точно знаете, какой должен быть тип, но нужно подстраховаться от ошибок.
Это хороший вариант, но больно пользоваться. Хочется более элегантного решения решения для этой проблемы. И оно есть! О этом в следующем посте.
Use a right semantic. Stay cool.
#cpp17