c++ - C++ API 设计:使用 void* 是个坏主意吗?
问题描述
我正在开发一个我希望在调用方尽可能通用的 API。主要设计思想是提供一种信号/插槽类型的实现,允许 API 的用户订阅给定的一组事件,并将用户定义的回调附加到它们。
公共接口看起来像这样:
RetCallback subscribe(EventEnum& ev, std::function<void(void*)> fn) const;
: 注意void(void*)
这里的签名。EventEnum
在公共头文件中给出,以及类型定义。
然后,API 的内部工作将通过 notify 方法通知其订阅的观察者事件,并提供数据以转发给客户端:
void dummyHeavyOperation() const {
std::this_thread::sleep_for(2s);
std::string data = "I am working very hard";
notify(EventEnum::FooEvent, &data);
}
客户端订阅并将数据转换为(记录的)类型,如下所示:
auto subscriber = Controller->subscribe(EventEnum::FooEvent, callback);
在哪里
void callback(void* data) {
auto* myData = (std::string*) data;
std::cout << "callback() with data=" << *myData << std::endl;
/// Do things
}
这是一个合理的设计还是不受欢迎?您经验丰富的现代 C++ 开发人员的头脑告诉您什么?
[编辑]
我还应该补充一点,API 是作为在运行时加载的共享库提供的。因此,任何编译时耦合(以及代码生成,除非我弄错了)都不在讨论范围内
谢谢!
解决方案
C++ API 设计:使用 void* 是个坏主意吗?
是的。
要实现等效的 API,您应该使用std::any
,这是类型擦除的检查版本。std::any
自当前的 C++17 标准版本以来,仅在标准库中可用。如果您没有 C++17(或不希望 API 的用户依赖 C++17),那么您可以使用非标准实现。
另一种方法是根本不删除参数类型,而是一直使用模板。有关此类回调 API 的示例,请参见Boost Signals
推荐阅读
- java - java语句的范围
- apache-kafka - SQS 风格的分布式延迟队列,但在 AWS 之外?
- regex - Regex 根据 Regex 将字符串拆分为 N 个匹配项
- python - 如何保存 Fbo 以用作画布的纹理?
- php - 如何在 IIS 服务器上获取有效的 DOCUMENT_ROOT 值?
- python - 打印 json 元素会导致 TypeError:列表索引必须是整数,而不是 str
- python - 为对象检测实现自定义损失函数
- angular - 在 Firestore 文档中为整数添加值
- sas - sas,压缩大数据集,节省unix服务器空间
- javascript - 使用 $regex 查询 mongoose 不返回任何结果