生成一百个 C 回调函数的模板,没有缓慢的编译
Template generating a hundred C callback functions, without slow compilation
我需要将一百个回调函数的顺序传递给 C 库。我的所有回调都将非常相似,只是它们需要知道它是为哪个“密钥”注册的。 C API 不允许传回上下文。
换句话说这是API:
void register_for_event(int event_type, void(*callback)());
我想到了这个模板元编程:
template<int event_type>
void event_handler() {
std::cout << "Event: " << event_type << std::endl;
}
template <int n = 100>
void register_event_handlers() {
register_for_event(n, event_handler<n>);
register_event_handlers<n-1>();
}
template<> void register_event_handlers<0>(){}
但是有没有办法这样写:
- 更容易阅读
- 编译速度更快(上面使用 gcc 增加了构建文件的时间)
任何版本的 C++,最高为 C++20,都适合我。
我试图避免使用宏,尽管我不清楚宏在这里有何帮助。
我可以使用 shell 脚本的代码生成。如果找不到更好的 C++ 本地方式,我可能最终会这样做。但我也对其他可能的原生 C++ 方式感兴趣。
这是一个 C++17 答案:
template <std::size_t... I>
void register_via_pack(std::index_sequence<I...>) {
( (register_for_event(I, event_handler<I>)),... );
}
register_via_pack(std::make_index_sequence<100>{});
它使用 C++17 折叠表达式扩展了模板参数包。不确定它在您的场景中是否编译得更快,但在 g++ -O3 下它快了 4 倍。即使在 -Og 下,它也会生成展开的代码而不是 100 层深度的递归。
您可以使用 the trick here 在 C++11/C++14 下执行相同的操作。
您可以通过使用立即调用的可变参数模板化 lambda 函数来摆脱额外的功能,但它不会更具可读性;)
我需要将一百个回调函数的顺序传递给 C 库。我的所有回调都将非常相似,只是它们需要知道它是为哪个“密钥”注册的。 C API 不允许传回上下文。
换句话说这是API:
void register_for_event(int event_type, void(*callback)());
我想到了这个模板元编程:
template<int event_type>
void event_handler() {
std::cout << "Event: " << event_type << std::endl;
}
template <int n = 100>
void register_event_handlers() {
register_for_event(n, event_handler<n>);
register_event_handlers<n-1>();
}
template<> void register_event_handlers<0>(){}
但是有没有办法这样写:
- 更容易阅读
- 编译速度更快(上面使用 gcc 增加了构建文件的时间)
任何版本的 C++,最高为 C++20,都适合我。
我试图避免使用宏,尽管我不清楚宏在这里有何帮助。
我可以使用 shell 脚本的代码生成。如果找不到更好的 C++ 本地方式,我可能最终会这样做。但我也对其他可能的原生 C++ 方式感兴趣。
这是一个 C++17 答案:
template <std::size_t... I>
void register_via_pack(std::index_sequence<I...>) {
( (register_for_event(I, event_handler<I>)),... );
}
register_via_pack(std::make_index_sequence<100>{});
它使用 C++17 折叠表达式扩展了模板参数包。不确定它在您的场景中是否编译得更快,但在 g++ -O3 下它快了 4 倍。即使在 -Og 下,它也会生成展开的代码而不是 100 层深度的递归。
您可以使用 the trick here 在 C++11/C++14 下执行相同的操作。
您可以通过使用立即调用的可变参数模板化 lambda 函数来摆脱额外的功能,但它不会更具可读性;)