您的位置:首页 > 娱乐 > 八卦 > 遵义在线论坛_装修网站平台排行榜_网络营销比较成功的企业_网络违法犯罪举报网站

遵义在线论坛_装修网站平台排行榜_网络营销比较成功的企业_网络违法犯罪举报网站

2024/12/23 5:16:28 来源:https://blog.csdn.net/CUBE_lotus/article/details/142441571  浏览:    关键词:遵义在线论坛_装修网站平台排行榜_网络营销比较成功的企业_网络违法犯罪举报网站
遵义在线论坛_装修网站平台排行榜_网络营销比较成功的企业_网络违法犯罪举报网站

文章目录

  • ⭐前言
  • ⭐expected
    • 🎛️基础使用
    • 🎛️单子操作 (Monadic operations)
      • 🎚️and_then & or_else
      • 🎚️transform & transform_error
  • ⭐END
    • 🌟跋
    • 🌟交流方式

⭐前言

在 C++17 中,提出了 optional 的可选项类型。但是该类型仅能表示二元状态,true | false 但在实际业务常见成功与否可以只用一个flag表示,但失败的原因却多种多样,需要以一种更丰富的形式表示。

因此在 C++23 中正式规范了std::expected,操作方式与原先的std::optional相似,又扩展了一些统一的处理方案。

同时这些方法在 C++23 中也为 std::optional 提供。

⭐expected

下面以一个获取星期几的字符串的demo为例子来表示。

🎛️基础使用

操作以使用 std::optional 一致,但这里多了一项 error 的选项。

#include <ctime>
#include <expected>
#include <iostream>
#include <string>
#include <typeinfo>enum struct ParseError : int {Below,  // (<0)Above   // (>6)
};std::expected<std::string, ParseError> get_weekDay(int d) {if (d < 0) {return std::unexpected(ParseError::Below);} else if (d > 6) {return std::unexpected(ParseError::Above);}// C++20 指定初始化std::tm t{.tm_wday = d};char    buffer[16];std::strftime(buffer, sizeof(buffer), "%A", &t);return std::string(buffer);
}void test(int d) {auto ex = get_weekDay(d);if (ex.has_value()) {std::cout << ex.value() << std::endl;} else {if (ex.error() == ParseError::Below) {std::cout << "ParseError::Below" << std::endl;} else if (ex.error() == ParseError::Above) {std::cout << "ParseError::Above" << std::endl;} else {std::cout << ex.value_or("ParseError") << std::endl;}}
}int main() {test(-1);test(0);test(114514);
}

🎛️单子操作 (Monadic operations)

下面仅对上面 demo 的 void test(int) 函数进行修改

一般来说 Monadic operations 会被翻译成一元操作,或者单目操作。不知道为什么std::expected - cppreference.com 这里翻译成单子操作。

🎚️and_then & or_else

and_then() 如果 *this:

  • 表示预期值,那么调用 f 并返回它的结果。

  • 否则返回一个包含非预期值的 std::expected 对象,以 *this 的非预期值初始化该值。

or_else 如果 *this:

  • 包含非预期值,那么以 *this 的非预期值作为实参调用 f 并返回它的结果。

  • 否则返回一个表示预期值的 std::expected 对象。

因此两者的使用非常灵活,使用得当可以非常遍历的进行链式编程。

这个写法让我回想起以前写 javascript 的时候。

void test(int d) {auto ex = get_weekDay(d);ex/*** 若存在预期值则返回给定的函数在其上的结果,否则返回 expected 本身*/.and_then([](const auto& e) -> std::expected<std::string, ParseError> {std::cout << "[and_then] Type:" << typeid(e).name() << std::endl;std::cout << e << std::endl;return {e};})/*** 若 expected 含有预期值则返回其自身,否则返回给定的函数在非预期值上的结果*/.or_else([](const auto& e) -> std::expected<std::string, ParseError> {std::cout << "[or_else] Type:" << typeid(e).name() << std::endl;if (e == ParseError::Below) {std::cout << "ParseError::Below" << std::endl;} else if (e == ParseError::Above) {std::cout << "ParseError::Above" << std::endl;} else {std::cout << "ParseError" << std::endl;}return std::unexpected{e};});
}

mingw-gcc 运行效果

[or_else] Type:10ParseError
ParseError::Below
[and_then] Type:NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
Sunday
[or_else] Type:10ParseError
ParseError::Above

🎚️transform & transform_error

transform() 如果 *this:

  • 表示预期值,那么调用 f 并返回一个包含预期值的 std::expected 对象,以 f 的结果初始化该值(或在结果类型是 void 时值初始化)。
  • 否则返回一个包含非预期值的 std::expected 对象,以 *this 的非预期值初始化该值。

transform_error() 如果 *this:

  • 包含非预期值,那么以 *this 的非预期值作为实参调用 f 并返回一个包含预期值的 std::expected 对象,以 f 的结果初始化该值。
  • 否则返回一个表示预期值的 std::expected 对象。

这两个基本可以被and_then & or_else取代。

主要区别在于,在成功调用时能保证返回一个std::expected,且依赖于 f 的返回值。

这是少有的在 C++ 中可以天然的允许链式编程的函数。

void test(int d) {auto ex = get_weekDay(d);ex/*** 若存在预期值则返回含有变换后的预期值的 expected,否则返回 expected 本身*/.transform([](const auto& e) -> std::expected<std::string, ParseError> {std::cout << "[transform] Type:" << typeid(e).name() << std::endl;std::cout << e << std::endl;return {e};})/*** 若含有预期值则返回 expected 本身,否则返回含有变换后非预期值的 expected*/.transform_error([](const auto& e) -> std::expected<std::string, ParseError> {std::cout << "[transform_error] Type:" << typeid(e).name() << std::endl;if (e == ParseError::Below) {std::cout << "ParseError::Below" << std::endl;} else if (e == ParseError::Above) {std::cout << "ParseError::Above" << std::endl;} else {std::cout << "ParseError" << std::endl;}return std::unexpected{e};});
}

mingw-gcc 运行效果

[transform_error] Type:10ParseError
ParseError::Below
[transform] Type:NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
Sunday
[transform_error] Type:10ParseError
ParseError::Above

⭐END

最后,如果像更深刻的体会这里的链式效果,建议将上面代码的 and_then & or_else 以相反的顺序调用一遍,会有不一样的效果。

这样可以帮助更好的理解调用的逻辑和设计出更好的代码。

🌟跋

ref:

标准库标头 expected

相关类型:

  • (C++17) any的使用与简单实现
  • (C++17) optional的使用
  • (C++17) variant的使用与union对比
  • (C++17) optional 的 3 种用法

🌟交流方式

⭐交流方式⭐ |C/C++|算法|设计模式|软件架构-CSDN社区

关注我,学习更多C/C++,python,算法,软件工程,计算机知识

B站:

👨‍💻主页:天赐细莲 bilibili

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com