std::optional

表示 一个值 存在 或 不存在,给单个类型做“可空标记“

头文件:<optional>

  • 有值:存储一个 T 类型对象
  • 无值:空状态(std::nullopt

1. 基础应用场景

可以用作成员变量类型,类中某些属性可选但非必选,不用默认值占位(-1,0等特殊值标识无效),语义更清晰。

示例:

1
2
3
4
5
6
7
8
class AgentMessage
{

private:
std::string message_id_;
std::optional<std::string> context_id_;
std::optional<std::string> task_id_;
};

这是一个agent消息体的示例。

  • message_id_必填消息唯一标识

  • context_id_/task_id_可选,代表上下文 ID、任务 ID,不存在则置 std::nullopt

2. 判断是否有值

两种写法等价:

1
2
3
4
5
6
7
8
9
10
if (opt1.has_value())
{
// 有值
}

// 重载了 bool 运算符,简写
if (opt1)
{
// 有值
}

3. 取值

(1)value()

**无值时抛异常 std::bad_optional_access**,适合确定一定有值的场景。

1
2
3
4
if (opt3)
{
int v = opt3.value();
}

(2)解引用 *

和普通指针用法一致,空状态直接未定义行为(崩溃)

1
2
3
4
if (opt3)
{
int v = *opt3;
}

(3)value_or(默认值)

为空时返回你指定的默认值,不会抛异常

1
int v = opt1.value_or(0); // 空 → 返回 0

std::variant<T1, T2, T3…>

同一时刻,只能存放模板参数列表中的「其中一种类型」,类型之间互斥,多种类型,多选一存储。
头文件:<variant>

类比:

  • C 语言老式 union(联合体)
  • std::variant = 类型安全的现代联合体

1. 使用场景

示例:A2A通信响应结构体,服务端返回的数据,**可能是任务对象 AgentTask,也可能是消息对象 AgentMessage**,这个类把两种结果包装到一起,对外提供统一的返回类型。

C++11兼容版:

1
2
3
4
5
6
7
8
class A2AResponse
{

private:
Type type_;
AgentTask task_;
AgentMessage message_;
};

同时持有两种实体,靠 type_ 区分当前有效数据

std::variant版本:

1
std::variant<AgentTask, AgentMessage> data;

2. 构造与赋值

1
2
3
4
5
6
7
8
9
10
11
#include <variant>
#include <string>

// 定义:可存 int / string
std::variant<int, std::string> var;

// 存入 int
var = 123;

// 存入 string(自动切换当前类型)
var = "hello variant";

3. 判断当前是哪种类型

std::holds_alternative<类型>(变量)

返回 bool,判断当前存储的是不是指定类型。

1
2
3
4
5
6
7
8
if (std::holds_alternative<int>(var))
{
// 现在存的是 int
}
else if (std::holds_alternative<std::string>(var))
{
// 现在存的是 string
}

4. 取值

std::get<类型>(变量)

类型取出数据。

类型不匹配 → 抛异常 std::bad_variant_access

1
2
3
4
if (std::holds_alternative<int>(var))
{
int val = std::get<int>(var);
}

补充:按索引取值

1
2
// 模板参数 0 = 第一个类型 int
int val = std::get<0>(var);

5. 访问器:std::visit

统一遍历 / 处理 variant 内所有可能类型,代码更优雅。

1
2
3
4
5
6
7
8
9
10
11
12
std::visit([](auto&& v) {
// v 自动推导为当前实际类型
using T = std::decay_t<decltype(v)>;
if constexpr (std::is_same_v<T, int>)
{
// 处理 int
}
else if constexpr (std::is_same_v<T, std::string>)
{
// 处理 string
}
}, var);