系统性掌握C++17容器四件套:std::optional, std::any, std::variant, std::tuple

昨天在写《深入探讨C++的高级反射机制(2):写个能用的反射库》的时候,正好遇到动态反射需要的类型擦除技术。所谓的类型擦除,就是在两个模块之间的接口层没有任何类型信息,实现两个模块之间安全的通信。可以理解为:
在这里插入图片描述
为了实现这个功能,于是用到了std::any这个工具。考虑到许多开发者分不清std::variant和std::any之间的区别,于是萌发了写一篇文章系统性介绍一下他们的想法。

传统上,C++17标准为C++的类型系统和容器库带来了重要的补充和改进,std::optional, std::any, 和 std::variant这三种类型被统称为“C++17容器三剑客”,本文将在C++11引入在C++17获得的增强的std::tuple也纳入介绍,系统性地揭示C++体系中这类容器的完整面貌。

1. std::optional —— 语义明确的可选值

std::optional是一个模板类型,它提供了一种表示“可能没有值”的方式。在C++17之前,程序员通常会使用指针、特殊值或者布尔标记来表达这种“可选”语义,这些方法都有其局限性和缺陷。std::optional的出现,让这种表达方式变得更加安全和直观。

1.1 std::optional的基本概念
std::optional可以看作是一个可能包含类型T的值的容器。它提供了一种检查是否存储了值的安全方式,并且可以用简洁的API访问该值或者处理值不存在的情况。

1.2 使用场景

  • 函数可能无法返回有效值时
  • 配置项可能未设置时
  • 缓存结果可能不存在时

1.3 基本用法

#include <optional>
#include <iostream>

std::optional<int> maybeGetInt(bool flag) {
   
    if (flag) {
   
        return 123; // 返回有效的int
    }
    return {
   }; // 返回一个空的optional
}

int main() {
   
    auto val = maybeGetInt(true);
    if (val) {
    // 检查是否含有值
        std::cout << "Value: " << *val << std::endl; // 解引用访问值
    }

    auto noVal = maybeGetInt(false);
    std::cout << "No value: " << noVal.value_or(-1) << std::endl; // 使用value_or提供默认值

    return 0;
}

2. std::any —— 类型安全的void*

对于需要存储任意类型的值,C++17提供了std::any。这个容器可以存储任何类型的单个值,并且能够在运行时安全地访问存储的值。这对于编写泛型代码或者需要类型擦除的场景非常有用。非常类似C语义中的void*,不过差别是void*本身不能直接存储对象,而std::any本身提供了存储对象的能力。当然,也可以用std::any存储指针类型。

2.1 std::any的基本概念
std::any可以存储任意类型的值,只要该类型是可复制的。使用std::any_cast可以试图取回原始类型的值,如果类型不匹配,会抛出std::bad_any_cast异常。

2.2 使用场景

  • 动态类型的API设计
  • 类型安全的容器
  • 简化类型擦除实现

2.3 基本用法

#include <any&g
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值