当前位置: 首页 > news >正文

C++17使用std::optional表示一个可能存在的值

文章目录

  • 前言
  • 返回一个bool值
  • 使用 std::optional 改写
  • 总结

前言

平时写代码会遇到一种传递参数特殊值标记特殊流程,或者函数返回值存在魔法数的情况,很需要一种标记参数或返回值状态的结构,那么在 C++17 标准下提供了 std::optional 这个模板类,可以表示一个值不存在的状态,一起来看看用法吧。

返回一个bool值

以下例子纯属虚构,只为说明问题,无实际意义

bool getBoolVal(int a, int b)
{
    int* n = new int;
    if (!n)
        return false;

    *n = 1;

    if (a + *n > b)
        return true;
    else
        return false;
}

int main()
{
    if (getBoolVal(10, 9))
        std::cout << 1 << std::endl;
    else
        std::cout << 1 << std::endl;

    return 0;
}

这个例子中的函数 getBoolVal 本意是想返回一个 bool 类型的判断结果,但是函数中有一些异常情况时,比如申请内存异常时,也会返回一个bool值,这是与原判断结果语义不同的,所以需要单独返回这种情况,如果也放到同一个返回值中会导致含义模糊,这时可以考虑使用引用变量参数来返回实际比较结果。

bool getBoolVal(int a, int b, bool& ret)
{
    int* n = new int;
    if (!n)
        return false;

    *n = 1;

    if (a + *n > b)
        ret = true;
    else
        ret = false;

    return true;
}

int main()
{
    bool ret = false;
    if (getBoolVal(10, 9, ret))
        std::cout << "error" << std::endl;
    else
    {
        if (ret)
            std::cout << 1 << std::endl;
        else
            std::cout << 0 << std::endl;
    }

    return 0;
}

这个引用参数 ret 使用起来有点不方便,那把两个值都返回怎么样,虽然C++不允许有多个返回值,但可以把它们包装成 std::pair 或者 std::tuple 来返回,再来改写一下:

std::pair<bool, bool> getBoolVal3(int a, int b)
{
    int* n = new int;
    if (!n)
        return {false, false};

    *n = 1;

    if (a + *n > b)
        return {true, true};
    else
        return {true, false};
}

int main()
{
    auto [err, ret] = getBoolVal(10, 9);
    if (err)
        std::cout << "error" << std::endl;
    else
    {
        if (ret)
            std::cout << 1 << std::endl;
        else
            std::cout << 0 << std::endl;
    }

    return 0;
}

这种方法把实际的返回值,搭配一个表示状态的 bool 变量,组成 std::pair 进行返回,基本上得到而来语义明确的目的,但是看起来还是不太优雅,而 std::optional 可以帮助我们实现类似的需求,并且代码看起来能更简洁一点。

使用 std::optional 改写

std::optional 本身是一个模板类:会有一个 std::nullopt

template <class T>
class optional;

它内部有两种状态,要么有一个T类型的值,要么用 std::nullopt 表示没有值,查看一个 std::optional 对象是否有值,可以用 has_value() 进行判断,当一个 std::optional 有值时,可以通过用指针的方式(*号和->号)来使用它,或者用 value()函数取它的值,下面我们用它来改写一下之前的实现:

std::optional<bool> getBoolVal4(int a, int b)
{
    int* n = new int;
    if (!n)
        return std::nullopt;

    *n = 1;

    if (a + *n > b)
        return true;
    else
        return false;
}


int main()
{
    std::optional<bool> ret = getBoolVal(10, 9);
    if (ret.has_value())
        std::cout << "error" << std::endl;
    else
    {
        if (ret.value())
            std::cout << 1 << std::endl;
        else
            std::cout << 0 << std::endl;
    }

    return 0;
}

使用了 std::optional 之后就把 bool 类型之前的两态变成了三态,很多类似的逻辑也被封装成了函数,使用它之后代码更清晰了,从此可以告别一些烦人的魔法数了,一些函数参数也可以使用 std::optional 来包装,用法类似,在此就不展开说了。

总结

  • std::optional 是一个模板类,可以表示一个可能存在的值
  • std::optional 的内部有两种状态,要么表示一个T类型的值,要么用 std::nullopt 表示没有值
  • 可以用 has_value() 判断一个 std::optional 是否有值,然后用 value() 函数取它表示的值

==>> 反爬链接,请勿点击,原地爆炸,概不负责!<<==

子未经历过,安知此文是鸡汤,子非我,安知我不知此文是鸡汤。意见向左的人往往在内心互道傻X,而现实生活中哪有什么绝对的对错,只是出发点和眼界不同罢了,即使是真理也有适用的环境,“两点之间线段最短”,这一定是对的吗?

相关文章:

  • 推荐一个C++枚举转字符串的开源项目magic_enum
  • 只问耕耘,不问收获,其实收获却在耕耘中
  • 一个月黑风高的夜晚紧急完成gitlab服务器数据迁移
  • SVN如何删除文件名包含空格的文件
  • std::uniform_real_distribution的一个bug引发的服务器崩溃
  • 参考开源项目实现一个简易的C++枚举转字符串的函数
  • git查看历史记录及修改内容
  • rm -rf 真是删库跑路的一把好手
  • 智能指针(三):weak_ptr浅析
  • float的精度和取值范围
  • linux环境下常用的打包、压缩、解压命令(tar、gzip、bzip2、zip)
  • MySQL数据库导入、导出、复制表、重命名表
  • Python操作Excel工作簿(\*.xlsx)
  • java对接银联商务公众号+服务窗支付(1)
  • java对接银联商务公众号+服务窗支付(2)
  • [ JavaScript ] 数据结构与算法 —— 链表
  • 【MySQL经典案例分析】 Waiting for table metadata lock
  • iBatis和MyBatis在使用ResultMap对应关系时的区别
  • IOS评论框不贴底(ios12新bug)
  • IP路由与转发
  • Linux编程学习笔记 | Linux IO学习[1] - 文件IO
  • linux学习笔记
  • magento 货币换算
  • Sass 快速入门教程
  • 利用阿里云 OSS 搭建私有 Docker 仓库
  • 数据可视化之 Sankey 桑基图的实现
  • 微服务核心架构梳理
  • 学习JavaScript数据结构与算法 — 树
  • 用 Swift 编写面向协议的视图
  • 用element的upload组件实现多图片上传和压缩
  • 如何用纯 CSS 创作一个货车 loader
  • 说说我为什么看好Spring Cloud Alibaba
  • !!【OpenCV学习】计算两幅图像的重叠区域
  • ###51单片机学习(2)-----如何通过C语言运用延时函数设计LED流水灯
  • #我与虚拟机的故事#连载20:周志明虚拟机第 3 版:到底值不值得买?
  • (Redis使用系列) Springboot 实现Redis消息的订阅与分布 四
  • (Redis使用系列) Springboot 整合Redisson 实现分布式锁 七
  • (定时器/计数器)中断系统(详解与使用)
  • (附源码)php投票系统 毕业设计 121500
  • (附源码)spring boot校园健康监测管理系统 毕业设计 151047
  • (附源码)spring boot智能服药提醒app 毕业设计 102151
  • (十六)Flask之蓝图
  • (转) Face-Resources
  • (转)创业家杂志:UCWEB天使第一步
  • .gitignore文件---让git自动忽略指定文件
  • .NET 4.0网络开发入门之旅-- 我在“网” 中央(下)
  • .NET MVC 验证码
  • .NET 中 GetHashCode 的哈希值有多大概率会相同(哈希碰撞)
  • ::什么意思
  • @RestControllerAdvice异常统一处理类失效原因
  • [14]内置对象
  • [2010-8-30]
  • [Angular 基础] - 指令(directives)
  • [C++] 如何使用Visual Studio 2022 + QT6创建桌面应用
  • [JavaWeb]——获取请求参数的方式(全面!!!)