An alternate solution to the posted one (though significantly less ergonomic, it reduces the nesting)
template <typename... Ts>
inline auto transform_all(auto &&fn, std::optional<Ts> &&...optionals)
-> std::optional<std::invoke_result_t<decltype(fn), Ts...>> {
bool is_error = (!optionals.has_value() || ...);
if (is_error) {
return std::nullopt;
}
return fn(std::forward<decltype(optionals)>(optionals).value()...);
}