c++ Expected用法

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.

相关推荐
码匠许师傅21 分钟前
【C++ 面试真题】聊聊 C++ 的序列容器
java·c++·面试
IT爱学堂27 分钟前
尚硅谷Java+AI大模型应用开发革新版本 2025年3月
java·开发语言·人工智能
C++ 老炮儿的技术栈31 分钟前
Qt5.9.1 Windows 完整开发环境搭建流程
开发语言·c++·windows·qt·编辑器·代码化
xcLeigh36 分钟前
Go入门:无类型常量与类型常量的区别
服务器·开发语言·golang
泡沫冰@42 分钟前
GO 语言基础
开发语言·算法·golang
键盘会跳舞1 小时前
C++:std::tuple 源码级深度拆解——变参模板、SFINAE与模板元编程核心技巧
开发语言·c++·sfinae·变参模板
bkspiderx1 小时前
从零开始:VS Code搭建C/C++开发环境全指南(Windows/macOS/Linux)
c语言·c++·windows·vs code·c/c++开发环境
东华万里1 小时前
第40篇C++核心基础与工程实践:从底层逻辑到避坑指南
开发语言·c++·面试·大学生专区
wuyk5552 小时前
第 6 章 FOC 完整系统整合:从算法到真机跑起来
c语言·开发语言·stm32·单片机·嵌入式硬件