Return errors as values with std::expected
Every fallible step returns std::expected, and the monadic chain passes errors through untouched.
std::expected<T, E> carries either a value or an error, so error paths stay visible in the type instead of hiding in exceptions or out-parameters. transform maps the value and passes errors through untouched.
#include <expected>
#include <iostream>
#include <string>
std::expected<int, std::string> parse(const std::string& s) {
try {
size_t pos = 0;
int v = std::stoi(s, &pos);
if (pos != s.size()) return std::unexpected("trailing characters");
return v;
} catch (...) {
return std::unexpected("not a number");
}
}
int main() {
auto ok = parse("21").transform([](int v) { return v * 2; });
std::cout << (ok ? std::to_string(*ok) : "error: " + ok.error()) << '\n';
auto bad = parse("21x").transform([](int v) { return v * 2; });
std::cout << (bad ? std::to_string(*bad) : "error: " + bad.error()) << '\n';
}
Observed output:
42
error: trailing characters
Try this: chain a second transform and watch the error skip both steps.
Facts verified 2026-11-04. The code on this page was compiled and run on the box with GCC 16.2.0 at -std=c++23 -Wall -Wextra; the outputs quoted are the observed outputs. MSVC was not tested.
Keep Exploring
Keep exploring the docs, samples, and free tools to continue your evaluation.
Score SPF, DKIM, DMARC, MTA-STS, TLS-RPT, and BIMI for any domain.
Review grounded audit, compare, fix-plan, and report excerpts before you wire the API into anything.
Jump from the workflow page into the quickstart, endpoint guides, and full OpenAPI reference.