std::expected用于处理"可能失败的操作",表示一个操作要么成功并返回一个值,要么失败并返回一个错误信息。结合了类型安全和错误处理的优点,可以替代传统错误码和异常。
测试下:
cpp
#include <expected>
// 返回成功时的 int,或失败时的 std::string 错误信息
static std::expected<int, std::string> divide(int a, int b) {
if (b == 0) {
return std::unexpected("Division by zero");
}
return a / b;
}
void testExpected(void) {
auto result = divide(10, 0);
// 判断是否有值
if (result.has_value()) { // 可简写为 if (result)
std::cout << "10 / 0 , Result: " << result.value() << "\n";
} else {
// 获取具体的错误信息
std::cout << "Error: " << result.error() << "\n";
}
// 提供默认值
int val = result.value_or(0);
std::cout << "val: " << val << std::endl;
}
运行:

ok. 还支持链式调用,比较方便。再测试下模拟登录:
cpp
// 模拟用户
struct User {
std::string name;
std::string password;
};
// 步骤 1: 查找用户
static std::expected<User, std::string> find_user(const std::string& username) {
if (username == "admin") {
return User{"admin", "123456"};
}
return std::unexpected("User not found: " + username);
}
// 步骤 2: 验证密码
static std::expected<User, std::string> validate_password(const User& user, const std::string& pwd) {
if (user.password == pwd) {
return user; // 验证通过,返回用户
}
return std::unexpected("Invalid password for user: " + user.name);
}
// 步骤 3: 生成 Token (使用 transform 进行值的转换)
static std::expected<std::string, std::string> generate_token(const User& user) {
return "Token_" + user.name + "_abc123";
}
// 测试链式调用
static void test_chained_login(const std::string& username, const std::string& pwd) {
std::cout << "--- Testing login for: " << username << " ---" << std::endl;
auto result = find_user(username)
.and_then([&pwd](const User& user) { // and_then的参数是一个Lambda 表达式
return validate_password(user, pwd);
}) // 这里还可以加or_else处理失败场景,试着抢救一下错误。
.transform([](const User& user) {
// transform 的 lambda 直接返回普通值,而不是 expected
return "Token_" + user.name + "_abc123";
});
// 统一处理最终结果
if (result) {
std::cout << "Login Success! Token: " << result.value() << "\n";
} else {
std::cout << "Login Failed! Error: " << result.error() << "\n";
}
}
void testExpected2(void) {
test_chained_login("admin", "123456");
test_chained_login("guest", "123456");
test_chained_login("admin", "wrong");
}
运行:

ok . 想修改下demo,测试下调用or_else。 如果校验密码不通过,但发现对方是女生,则让她通过。
user加一个性别字段:
cpp
struct User {
std::string name;
std::string password;
std::string gender; // "male" 或 "female"
};
修改find_user, 假设admin用户是女生:
cpp
static std::expected<User, std::string> find_user(const std::string& username) {
if (username == "admin") {
return User{"admin", "123456", "female"};
}
return std::unexpected("User not found: " + username);
}
修改执行流程,加上密码校验失败时的or_else处理:
cpp
static void test_chained_login2(const std::string& username, const std::string& pwd) {
std::cout << "--- Testing login for: " << username << " ---" << std::endl;
// 1. 先拿到 find_user 的结果
auto user_result = find_user(username);
// 2. 开始链式调用
auto result = user_result
.and_then([&](const User& user) {
return validate_password(user, pwd);
})
.or_else([&](const std::string& err) -> std::expected<User, std::string> { // 注意,这个lambda表达式需要显式指定返回值类型,否则推导失败,报错:inconsistent types 'std::expected<User, std::__cxx11::basic_string<char> >' and 'std::unexpected<std::__cxx11::basic_string<char> >' deduced for lambda return type
std::cout << ">>> 密码校验失败,触发 or_else 抢救机制...\n";
if (user_result.has_value() && user_result->gender == "female") {
std::cout << ">>> 发现是女生,热烈欢迎!\n";
return std::expected<User, std::string>(user_result.value());
}
std::cout << ">>> 不是女生,继续拦截。\n";
return std::unexpected<std::string>(err);
})
.transform([](const User& user) {
return "Token_" + user.name + "_abc123";
});
if (result) {
std::cout << "Login Success! Token: " << result.value() << "\n\n";
} else {
std::cout << "Login Failed! Error: " << result.error() << "\n\n";
}
}
void testExpected2(void) {
// test_chained_login("admin", "123456");
// test_chained_login("guest", "123456");
// test_chained_login("admin", "wrong");
test_chained_login2("admin", "mimi");
}
测试:

ok.