You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

std::any_cast将void*转为函数指针时抛出bad_any_cast错误求解

问题原因与解决方案

1. 两个判定条件不成立的原因

std::any要求类型严格匹配才允许any_cast转换,不存在隐式类型转换逻辑,两个条件失败的核心是存入与取出的类型完全不匹配:

  • 你调用dlsym得到的返回值类型是void*,赋值给std::any时,实例内部存储的类型为void*,对应的类型标识是typeid(void*),关联的管理器也是std::any::_Manager<void*>的实例
  • 你any_cast的目标类型是void(*)(),属于无参数无返回值的函数指针类型,和void*是C++中完全独立的两种类型,因此__any->type() == typeid(_Tp)比对为假,对应的管理器地址也不可能相等,两个条件都不满足,最终返回nullptr抛出bad_any_cast。

你提供的最简Demo可以直接验证这个逻辑:你存入std::any的是强转为void*的函数地址,取出时却要转换为函数指针类型,类型不匹配自然会报错。

2. 保留std::any的修复方案

有两种常用方案可选,都符合POSIX标准下的实现要求:

方案1:存入时提前转换为目标函数指针类型

如果存入时已经知道函数的签名,直接将dlsym返回的void*转成对应函数指针类型再存入std::any,后续any_cast直接用对应类型取即可。
示例代码:

// 存值时转换
symbols_["foo"] = reinterpret_cast<void(*)()>(dlsym(handle_, "foo"));

// 取值时直接转换
return std::any_cast<void(*)()>(symbols_["foo"])();

对应Demo修复版:

#include <any>

void func() { }

auto main() -> int {
    std::any a = reinterpret_cast<void(*)()>(func);
    std::any_cast<void(*)()>(a)();
    return 0;
}

方案2:取出时先转回void*再手动转函数指针

如果存储时无法提前确定函数签名,可以统一存dlsym返回的void*,取值时先转成void*再手动强转为对应函数指针类型。
示例代码:

// 存值时直接存dlsym返回值
symbols_["foo"] = dlsym(handle_, "foo");

// 取值时两步转换
void* raw_ptr = std::any_cast<void*>(symbols_["foo"]);
return reinterpret_cast<void(*)()>(raw_ptr)();

注意:C++标准本身没有规定void*和函数指针的互转逻辑,上述转换是POSIX标准的扩展要求,在Linux、macOS等符合POSIX规范的系统下可安全使用,转换时必须保证函数签名和实际符号的签名完全一致,否则会触发未定义行为。

内容的提问来源于stack exchange,提问作者Nana Noe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 08:09:03