在 C++23 中对 std::expected 使用 std::apply

在 C++23 中对 std::expected 使用 std::apply
在 C++23 中对 std::expected 使用 std::apply

简化 C++23 中的错误处理

有效处理错误和管理返回值对于当今的 C++ 开发至关重要。使用返回 {std::expected} 类型的函数的典型方法包括大量检查和错误处理代码,这会使逻辑复杂化并使代码更难以维护。

本文研究了使用更复杂和更通用的方法来简化错误管理。为了减少样板代码并提高可读性,我们将研究构建一个“magic_apply”方法,该方法聚合许多 {std::expected} 值的结果并将它们传递给另一个函数。

命令 描述
std::expected C++ 中用于错误处理的模板类型,能够存储值和错误。
std::unexpected 与 std::expected 一起使用时,表示意外的错误值。
template<typename...> 概述了一个可变参数模板,其中包含可以接受的无限数量的模板参数。
decltype 用于模板编程,特别是找出表达式的类型。
args.value() 如果 std::expected 对象有值,则访问其中包含的值。
args.has_value() 验证 std::expected 对象中是否存在值。
(... && args.has_value()) 要确定每个 std::expected 对象是否都有值,请折叠表达式。
func(args.value()...) 使用 std::expected 对象的值来调用方法 func。
return unexpected<Err>(args.error()...) 返回一个意外错误,其中包含来自 std::expected 对象的错误。

使用变量模板进行有效的错误管理

std::expected 脚本中使用 type 来简化 C++23 中的错误处理。主要目标是开发一个名为的通用函数 magic_apply 可以传输多个输出 std::expected 值到另一个函数。通过这样做,在处理许多问题时通常需要进行繁琐的错误检查 std::expected 值减少。 magic_apply 非常灵活,因为它可能需要任意数量的 std::expected 通过使用可变参数模板来设置参数。在使用任何内容调用该函数之前 std::expected 对象,基本逻辑 magic_apply 使用折叠表达式, (... && args.has_value()),以确保所有 std::expected 对象具有有效值。

第一个脚本示例使用简单类型(例如 intdouble。它定义了一个 compute_all 执行基本计算的函数,以及 getAgetB 返回的函数 std::expected 类型。如果两个值都来自 getAgetB 是合法的,我们可以调用 compute_all 使用 magic_apply;如果不是,则传播错误。通过减少样板代码,该方法增强了可读性和可维护性。第二个脚本中提出了类似的想法,但为了强调该方法的多功能性, string 类型和 lambda functions 被使用。

使用 `std::expected} 降低 C++ 错误处理的复杂性

使用可变参数模板的 C++23 脚本

#include <expected>
#include <string>
#include <iostream>
#include <tuple>

using namespace std;

template<typename Func, typename... Args, typename Err>
auto magic_apply(Func func, const expected<Args, Err>&... args) -> expected<decltype(func(args.value()...)), Err> {
    if ((... && args.has_value())) {
        return func(args.value()...);
    } else {
        return unexpected<Err>(args.error()...);
    }
}

expected<int, string> getA(int x) {
    if (x > 0) return x;
    return unexpected<string>("Error in getA");
}

expected<double, string> getB(double y) {
    if (y > 0) return y;
    return unexpected<string>("Error in getB");
}

double compute_all(int a, double b) {
    return a + b;
}

int main() {
    auto result = magic_apply(compute_all, getA(10), getB(20.5));
    if (result) {
        cout << "Result: " << result.value() << endl;
    } else {
        cout << "Error: " << result.error() << endl;
    }
    return 0;
}

组合不同的 {std::expected} 结果 C++23 值

使用 Lambda 函数的 C++23 脚本

#include <expected>
#include <string>
#include <iostream>

using namespace std;

template<typename Func, typename... Args, typename Err>
auto magic_apply(Func func, const expected<Args, Err>&... args) -> expected<decltype(func(args.value()...)), Err> {
    bool all_valid = (args.has_value() && ...);
    if (all_valid) {
        return func(args.value()...);
    } else {
        return unexpected<Err>(args.error()...);
    }
}

expected<string, string> getA(bool flag) {
    if (flag) return "SuccessA";
    return unexpected<string>("Failed A");
}

expected<string, string> getB(bool flag) {
    if (flag) return "SuccessB";
    return unexpected<string>("Failed B");
}

string compute_all(const string& a, const string& b) {
    return a + " and " + b;
}

int main() {
    auto result = magic_apply(compute_all, getA(true), getB(true));
    if (result) {
        cout << "Result: " << result.value() << endl;
    } else {
        cout << "Error: " << result.error() << endl;
    }
    return 0;
}

使用可变参数模板改进 C++ 错误处理

容量为 std::expected 在 C++ 中使用它的另一个重要好处是大大增强复杂系统中的错误处理能力。在许多异步操作产生结果的情况下,无缝组合它们的结果至关重要 std::expected 类型。除了使代码更简单之外,此方法还保证了强大的错误处理能力。通过组合任意数量的函数可以创建更通用和通用的函数 std::expected 价值观与 variadic templates

的多功能性 magic_apply 允许它与接受各种参数类型的函数一起使用。通过利用,实现进一步变得更简单 decltype,它自动推导组合函数调用的返回类型。此外,该技术可以扩展到管理更复杂的任务,包括合并 std::expected 具有其他错误类型的值或在将值发送到函数之前更改值。由于其适应性,该模式可用于广泛的任务,从简单的计算到复杂的操作。

有关可变参数模板和 std::expected 的常见问题

  1. 什么是 std::expected
  2. 它是一种 C++ 模板类型,可以保存错误或有效值,并用于错误管理。
  3. 怎么样 magic_apply 工作?
  4. 它通过结合大量结果来消除重复错误检查的需要 std::expected 值并将它们传递给函数。
  5. 什么是可变参数模板?
  6. 变量模板使函数能够接受任意数量的参数,从而为函数设计提供了很大的自由度。
  7. 为什么使用 decltypemagic_apply
  8. 利用的值 std::expected 对象自动确定被调用函数的返回类型。
  9. magic_apply 能够处理各种错误类型?
  10. 是的,它可以与以下功能一起使用 std::expected 具有各种错误类型的值,只需进行一些调整即可。
  11. 利用什么优势 std::expected 提供?
  12. 在处理错误时,它提供了比异常或返回代码等更传统的技术更具表现力和更简洁的方法。
  13. std::unexpected 的一部分 std::expected
  14. 此外 std::expected, std::unexpected 事实上,它代表了一个不正确的值。
  15. 可以使用异步操作吗 magic_apply
  16. 它确实能够适应处理 std::expected 异步操作返回的值。
  17. 什么是折叠表达式?
  18. 这里,C++ 中称为折叠表达式的功能用于检查是否所有 std::expected 对象以简单的方式包含有效值。

总结:

C++23 中,实现泛型函数来处理多个 std::expected 值极大地提高了代码可读性并大大简化了错误处理。 magic_apply 函数通过使用可变参数模板来减少样板代码并增强可维护性,以确保在处理之前所有预期值都是正确的。这种方法提供了一种灵活的解决方案,可以应用于不同的情况,并为现代 C++ 编程提供了一种更干净、更有效的方法来处理故障。