如何在C++中模拟JavaScript的可选链运算符?
在C++中用宏模拟JS可选链运算符
完全可以通过G++/Clang支持的可变参数宏结合C17特性,实现类似request?.full_price?.fees?.tax的可选链操作,且无需显式或隐式提及任何类型名称。核心思路是通过宏展开链式访问逻辑,每一步自动检查当前对象是否非空,为空则终止调用并返回空状态,否则继续访问下一层成员。
宏实现代码
#include <optional> // 辅助函数:检查指针有效性,返回成员的optional包装值 template<typename T, typename MemPtr> auto opt_deref_step(T* obj, MemPtr mem_ptr) { using ResultType = std::decay_t<decltype((*obj).*mem_ptr)>; return obj ? std::make_optional((*obj).*mem_ptr) : std::optional<ResultType>{}; } // 可变参数宏,展开链式可选访问 #define OPT_DEREF(obj, ...) \ [&]() { \ auto current = std::make_optional(obj); \ ((current = current ? opt_deref_step(&*current, &std::decay_t<decltype(*current)>::__VA_ARGS__) : std::nullopt), ...); \ return current; \ }()
用法示例
假设你有如下嵌套结构体(自动生成的序列化结构):
struct Tax { double amount; }; struct Fees { Tax* tax; }; struct FullPrice { Fees* fees; }; struct Request { FullPrice* full_price; };
使用OPT_DEREF宏模拟可选链:
Request* request = get_service_request(); // 可能返回nullptr // 等价于JS的request?.full_price?.fees?.tax?.amount auto tax_amount = OPT_DEREF(request, full_price, fees, tax, amount); if (tax_amount) { printf("Tax amount: %.2f\n", *tax_amount); } else { printf("Tax data is missing in request\n"); }
核心逻辑说明
- 辅助函数
opt_deref_step:接收当前对象指针和成员指针,判断指针非空后返回成员的std::optional包装值,为空则返回空的optional。 - 宏展开逻辑:
- 用lambda表达式包裹逻辑,避免全局变量污染;
- 初始将输入对象包装为
std::optional; - 通过C++17折叠表达式依次处理每个成员:若当前
optional有效,就调用辅助函数获取下一层成员的optional,否则保持空状态; - 最终返回包含最终成员值的
std::optional,为空则表示链式调用中某一步出现空指针。
注意事项
- 要求编译器支持C17及以上(G 7+、Clang 5+均满足);
- 仅适用于指针类型的成员(对应JS可选链处理的null/undefined场景);
- 返回值为
std::optional<T>,需通过if (opt)或opt.has_value()判断有效性后访问内部值。
内容的提问来源于stack exchange,提问作者Tomilov Anatoliy
相关产品推荐
相关产品推荐

