带有运行时参数的桥接模板

bridging templates with runtime arguments

本文关键字:桥接 参数 运行时      更新时间:2023-10-16

我正在处理第三方C 库,该库可广泛使用模板。这使得很难创建C API以从我的框架中使用它。

抽象问题,假设库提供了该功能:

template <int i> void foo();
template <int i> void zoo(int v);

我想用功能头创建C API:

extern "C" void c_foo(int i);
extern "C" void c_zoo(int i, int v);

明显的实现可能是:

void c_foo(int i)
{
     switch(i) {
         case 1: foo<1>(); break;
         case 2: foo<2>(); break;
         case 3: foo<3>(); break;
         default: break;
     };
};

,也为void zoo(int)做同样的事情。

如果i的可能值较小,则可以正常工作。如果我想处理[1,100]中的i的所有可能值,那么以这种方式编写代码变得非常丑陋,因为有很多重复。

还有其他紧凑的方法可以做到这一点,即编写较少的代码行?也许使用递归预处理器宏?

您可以内部使用模板来生成必要的代码。

做到这一点的一种方法是生成100个功能指针的调度表,然后在运行时索引。c_foo将生成一个编译时间的索引序列,并致电助手:

extern "C" void c_foo(int i) {    
    c_foo_impl(std::make_integer_sequence<int,100>{}, i);
}

该助手将生成调度表并进行呼叫:

template <int... Is>
void c_foo_impl (std::integer_sequence<int,Is...>, int i) {
    constexpr std::array<void(*)(), sizeof...(Is)> dispatch = { &foo<Is>... };
    //assert or some other error handling for i > sizeof...(Is)
    dispatch[i]();
}

然后您可以为zoo做同样的事情:

extern "C" void c_zoo(int i, int v) {   
    c_zoo_impl(std::make_integer_sequence<int,100>{}, i, v);
}
template <int... Is>
void c_zoo_impl (std::integer_sequence<int,Is...>, int i, int v) {
    constexpr std::array<void(*)(int), sizeof...(Is)> dispatch = { &zoo<Is>... };
    //assert or some other error handling for i > sizeof...(Is)
    dispatch[i](v);
}

如果您发现在几个地方需要它,则可以抽象一些细节,或使用Petra等库,该图书馆提供switch_table进行此类映射。

实时演示

我想问题是这个模板号是什么?它是内部缓冲区大小还是更像命令字节?人们假设平均C 程序只会生成一定的参数值。

也许bast方法是枚举一些典型的缓冲区大小或命令名称,并仅实例化,因此,如果C代码使用您的枚举作为参数将起作用,否则(可怕地)断言。p>如果有理由添加新条目是一个烦人的事情,但是您可以为其编写一个脚本。

另一种方法可能是生成命名为Stubs的混杂,即生成Foo__1()foo__2()等,也许使用Boost扩展的预处理器来提供帮助。然后,C程序员再次将其自动限于您在编译时发布的方法和范围。