首页 > 解决方案 > 在 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 语句和函数指针类型转换?我已经看到luawrapperBinder类做了类似的事情。但是代码相当复杂。在我的情况下,参数都是相同的类型。最后我想做一些类似(伪代码)的事情:

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++templates

解决方案


好吧,如果它们只是 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()并在里面存储适当的函数类型。

活生生的例子


推荐阅读