使用运行时参数桥接模板

Fab*_*bio 2 c c++ templates c-preprocessor c++11

我正在处理第三方C++库,它广泛使用模板.这使得很难为我的框架使用它创建一个C API.

提取问题,假设库提供了以下功能:

template <int i> void foo();
template <int i> void zoo(int v);
Run Code Online (Sandbox Code Playgroud)

我想用函数头创建一个C API:

extern "C" void c_foo(int i);
extern "C" void c_zoo(int i, int v);
Run Code Online (Sandbox Code Playgroud)

一个明显的实现可能是:

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

并做同样的事情void zoo(int).

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

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

Tar*_*ama 5

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

一种方法是生成一个包含100个函数指针的调度表,然后在运行时对其进行索引.c_foo将生成一个编译时索引序列并调用一个帮助器:

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

这个帮助器将生成调度表并执行调用:

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]();
}
Run Code Online (Sandbox Code Playgroud)

然后你可以做同样的事情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);
}
Run Code Online (Sandbox Code Playgroud)

如果你发现在一些地方需要这个,你可以抽象出一些细节,或者使用像Petra这样的库,它提供了一个switch_table执行这种映射的库.

现场演示