c++ - 如何使用未知数量的参数指定指向 C 函数的 C++ 指针?
问题描述
我正在编写一个 C 库,我希望它可以在 C 和 C++ 中使用。在某一时刻,它应该从用户那里接受一个带有 0-3 个参数的回调,稍后将在某个指针处调用它。像这样(代码的副本也可以作为GitHub Gist获得):
// app_c.c
#include <stdio.h>
#include "lib.h"
double f0(void) {
return 123;
}
double f2(double a, double b) {
return a + b;
}
int main() {
cb_arity = 0;
cb_func = f0;
printf("%f\n", cb_call());
cb_arity = 2;
cb_func = f2;
printf("%f\n", cb_call());
}
我能够创建一个指向 C 函数的指针,该函数接受未知(但仍然固定)数量的参数,注意它是void (*cb_func)()
,而不是void (*cb_func)(void)
:
// lib.h
#ifndef LIB_H_
#define LIB_H_
#ifdef __cplusplus
extern "C" {
#endif
extern int cb_arity;
extern double (*cb_func)();
double cb_call(void);
#ifdef __cplusplus
}
#endif
#endif // LIB_H_
// lib.c
#include "lib.h"
#include <stdlib.h>
int cb_arity;
double (*cb_func)();
double cb_call(void) {
switch (cb_arity) {
case 0:
return cb_func();
case 1:
return cb_func(10.0);
case 2:
return cb_func(10.0, 20.0);
case 3:
return cb_func(10.0, 20.0, 30.0);
default:
abort();
}
}
它可以在我的机器和Wandbox上成功编译和运行。据我了解,没有调用 UB。
现在我想让它也可以在 C++ 中工作。不幸的是,看起来我现在需要reinterpret_cast
,因为()
在 C++ 中意味着“无参数”,而不是“未知数量的参数”:
// app_cpp.cpp
#include <stdio.h>
#include "lib.h"
int main() {
cb_arity = 0;
cb_func = []() { return 123.0; };
printf("%f\n", cb_call());
cb_arity = 2;
cb_func = reinterpret_cast<double(*)()>(static_cast<double(*)(double, double)>(
[](double a, double b) { return a + b; }
));
printf("%f\n", cb_call());
}
据我了解,这里也没有调用 UB:虽然我将函数指针转换double(*)(double, double)
为double(*)(void)
C++ 中的函数指针,但在调用之前它已转换回double(*)(double, double)
C 代码中。
有什么办法可以摆脱 C++ 代码中这些丑陋的演员表吗?我试过指定cb_func
as的类型void(*)(...)
,但 C++ 仍然不会隐式转换double(*)(double, double)
为它。
解决方案
您可以保留它,而不是从回调中删除参数的数量。
// lib.h
#ifndef LIB_H_
#define LIB_H_
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
int arity;
union {
void(*zero)(void);
void(*one)(double);
void(*two)(double, double);
void(*three)(double, double, double);
}
} cb_type;
extern cb_type cb;
double cb_call(void);
#ifdef __cplusplus
}
#endif
#endif // LIB_H_
// lib.c
#include "lib.h"
#include <stdlib.h>
cb_type cb;
double cb_call(void) {
switch (cb.arity) {
case 0:
return cb.zero();
case 1:
return cb.one(10.0);
case 2:
return cb.two(10.0, 20.0);
case 3:
return cb.three(10.0, 20.0, 30.0);
default:
abort();
}
}
如果您不公开cb
,则不能不匹配 arity 和 union 成员:
// lib.h
#ifndef LIB_H_
#define LIB_H_
#ifdef __cplusplus
extern "C" {
#endif
void register_zero(void(*)(void));
void register_one(void(*)(double));
void register_two(void(*)(double, double));
void register_three(void(*)(double, double, double));
double cb_call(void);
#ifdef __cplusplus
}
#endif
#endif // LIB_H_
推荐阅读
- reactjs - 访问 React Dropzone 组件上的“名称”属性
- ruby - 乘法问题:除以相同的小数并乘以不返回原始数字
- ms-word - 如何禁用保存、另存为或 ctr+c unsing office-js
- testing - Rego测试:如何测试“不否认”?
- javascript - React hooks - 由于关闭而使用旧状态异步更新 setState
- java - getSystemId() 的返回值
- javascript - 在对象中键入 svg 元素做出反应
- android - 无法覆盖firebase数据库
- google-chrome - 从 vscode 和 chrome 调试 firebase auth 应用程序不起作用
- java - 我不确定为什么我的键绑定不起作用。[Java 键绑定]