c++ - 在 C++ 中通过模板包重新创建函数签名和调用
问题描述
我有想用 C++ 重写的 C 代码。C 代码是解释器的一部分,其中函数在 C 中定义,但实际调用来自解释源。基本上它的作用如下:
#include <vector>
void f1(int a0) { }
void f2(int a0,int a1) { }
void f3(int a0,int a1,int a2) { }
void f4(int a0,int a1,int a2,int a3) { }
struct m {
void *p;
int c;
};
std::vector<m> ma;
int addfunc(void *p, int c) {
int i = ma.size();
ma.push_back({p,c});
return i;
}
void call(int idx, int *stack) {
switch (ma[idx].c) {
case 1:
((void (*)(int))ma[idx].p) (stack[0]);
break;
case 2:
((void (*)(int,int))ma[idx].p) (stack[0],stack[1]);
break;
case 3:
((void (*)(int,int,int))ma[idx].p) (stack[0],stack[1],stack[2]);
break;
case 4:
((void (*)(int,int,int,int))ma[idx].p) (stack[0],stack[1],stack[2],stack[3]);
break;
}
}
int main (void) {
int stack[5] = { 0,1,2,3,4 };
/* define */
int i1 = addfunc((void*)f1, 1);
int i2 = addfunc((void*)f2, 2);
int i3 = addfunc((void*)f3, 3);
int i4 = addfunc((void*)f4, 4);
/* call */
call(i1,stack);
call(i2,stack);
call(i3,stack);
call(i4,stack);
}
创建一个由函数指针和签名指定的addfunc
可调用对象,因为参数的类型相同,只需要一个用于参数数量的计数参数。当我call
是一个函数时,我指定函数对象的索引和一个stack
. 实际的 c 调用通过参数计数和类型转换进行解码,调用参数从堆栈中获取。
如何在 C++中将addfunc
和函数重写为模板对象?call
如何使用模板包计算给定函数的参数数量并重新生成对函数的调用?
如何摆脱 switch 语句和函数指针类型转换?我已经看到luawrapper的Binder
类做了类似的事情。但是代码相当复杂。在我的情况下,参数都是相同的类型。最后我想做一些类似(伪代码)的事情:
vector<meth> ma;
...
int i0 = addfunc([](int a) { });
int i1 = addfunc([](int a,int b) { });
int i2 = addfunc([](int a,int b,int b) { });
int i3 = addfunc([](int a,int b,int c,int c) { });
...
ma[i0](stack);
ma[i1](stack);
ma[i2](stack);
ma[i3](stack);
解决方案
好吧,如果它们只是 C 函数,为什么不在函数指针类型上重载呢?
std::function<void(std::array<int, 5>)> addfunc(void (*f)(int)) {
return [f](std::array<int, 5> const& a) { f(a[0]); };
}
std::function<void(std::array<int, 5>)> addfunc(void (*f)(int,int)) {
return [f](std::array<int, 5> const& a) { f(a[0], a[1]); };
}
// repeat for all necessary arities
然后创建std::vector<std::function<void(std::array<int, 5>)>>
并推回您的所有功能。这很容易,不需要任何模板,并且可以很好地工作。但是,它引入了 的开销std::function
。
你可以通过引入你自己的可调用类型(其中 n 个)来摆脱它,它对应于上面的重载,提供operator()
并在里面存储适当的函数类型。
推荐阅读
- asp.net-core - Wsfederation 错误。令牌过期后,注册用户的注册表单不断弹出
- java - 使用 Android Studio,为什么包含在 LinearLayout 小部件中的 TextView 显示被截断?
- react-native - React Native:文本字符串必须在
零件 - javascript - 如何抽象现有的 firebase CRUD 操作,以便能够迁移到 node.js 中的另一个数据库
- amazon-s3 - 如何列出存储桶中所有对象的版本及其各自的元数据 (x-amz-meta-version)
- django - Django查询集过滤器基于父级的父级
- c++ - 我的 c++ 程序没有输入就终止了。我该怎么办?
- c# - 我的数据库项目的gridview和更新仍然有问题
- javascript - 抛出“requirejs is not defined”错误怎么办?
- aws-lambda - 我们如何强制 AWS Lamda 在 VPC 中安全运行?