如何无需类型检查直接调用std::variant所持类型的共有成员函数
实现方法
完全不需要手动判定var的持有类型,直接使用C++17随std::variant同步引入的std::visit即可实现自动分发调用,这也是标准库针对variant访问给出的标准实现方案。
需要注意你的variant包含std::monostate空状态,该类型没有func()成员,必须单独给出对应处理逻辑,否则会编译失败。
C++17 及以上通用写法
最简洁的实现是配合泛型lambda + if constexpr编译期分支判断,代码如下:
#include <variant> // 自定义类型示例 struct first_custom_type { void func() { /* 你的业务逻辑 */ } }; struct second_custom_type { void func() { /* 你的业务逻辑 */ } }; int main() { std::variant<std::monostate, first_custom_type, second_custom_type> var; // 初始化var的逻辑,比如赋值为second_custom_type实例 var = second_custom_type{}; std::visit([](auto&& arg) { using RealType = std::decay_t<decltype(arg)>; // 单独处理空状态 if constexpr (std::is_same_v<RealType, std::monostate>) { // 空状态下的处理逻辑,比如直接返回、抛出异常均可 return; } else { // 其余实现了func()的类型直接调用即可 arg.func(); } }, var); }
如果不想写编译期分支,也可以用重载访问者的写法,先定义一个简单的辅助重载模板:
template<class... Fns> struct overloaded : Fns... { using Fns::operator()...; }; template<class... Fns> overloaded(Fns...) -> overloaded<Fns...>;
调用时代码结构更清晰:
std::visit(overloaded{ [](std::monostate) { /* 空状态处理逻辑 */ }, [](auto& valid_val) { valid_val.func(); } }, var);
方案优势
- 所有分支检查在编译期完成,不会出现运行时漏判类型的问题,比手动写
std::holds_alternative+std::get的判断逻辑安全性高很多 - 后续如果给variant新增其他同样实现了
func()的类型,不需要修改访问逻辑,代码可维护性更好 - 不会有额外的运行时判断开销,编译器生成的代码和你手动写类型分支的效率完全一致
内容的提问来源于stack exchange,提问作者h8n2
相关产品推荐
相关产品推荐

