使用运行时参数桥接模板

2024-04-02

我正在处理一个广泛使用模板的第三方 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是小。如果我想处理所有可能的值i在[1,100]中,那么用这种方式编写代码就变得非常难看,因为有很多重复。

有没有更紧凑的方法来做到这一点,即编写更少的代码行?也许使用递归预处理器宏?


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

一种方法是生成一个包含 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 https://github.com/jacquelinekay/petra,它提供了一个switch_table来进行这种映射。

现场演示 http://coliru.stacked-crooked.com/a/a30814607651e96e

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用运行时参数桥接模板 的相关文章

随机推荐