如何将C++可变参数模板整数自动生成高效switch语句?
如何自动生成枚举可变参数模板参数的switch语句
我们有一个依赖模板参数key的函数bar,以及一个接受可变模板参数的函数foo,希望调用foo<1,3,5,7,9>(key)时,自动生成包含所有模板参数的switch分支,无需手动编写每个case。
原始代码
// 依赖key模板参数执行逻辑的函数 template <int key> void bar() {...} template <int ...Keys> void foo(int key) { // 这里需要自动生成代码 } std::cin >> key; foo<1,3,5,7,9>(key);
期望生成的代码
template <int ...Keys> void foo(int key) { switch (key) { case 1: bar<1>();break; case 3: bar<3>();break; case 5: bar<5>();break; case 7: bar<7>();break; case 9: bar<9>();break; default: break; } }
解决方案
C++17及以上:折叠表达式实现
利用C++17引入的折叠表达式,配合逗号运算符可以简洁地展开参数包,生成等价于switch的分支逻辑:
template <int ...Keys> void foo(int key) { switch(key) { // 折叠表达式逐个匹配模板参数,匹配时调用对应bar并终止后续检查 ((key == Keys ? (bar<Keys>(), true) : false) || ...); default: break; } }
这种写法通过||折叠特性,只要有一个参数匹配成功,后续检查就会停止,和switch的行为完全一致,代码简洁且高效。
如果想要更贴近原生switch的写法,也可以用C++20的模板lambda:
template <int... Keys> void foo(int key) { [&]<int K>() { switch(key) { case K: bar<K>(); break; } }.template operator()<Keys>()...; }
C++11/14:递归模板实现
如果编译器不支持C++17,可以用递归模板逐个展开参数包:
// 递归终止模板:无参数时什么都不做 template<int...> struct SwitchGenerator { static void generate(int) {} }; // 递归展开模板参数:处理第一个参数后递归处理剩余参数 template<int First, int... Rest> struct SwitchGenerator<First, Rest...> { static void generate(int key) { if (key == First) { bar<First>(); } else { SwitchGenerator<Rest...>::generate(key); } } }; template <int ...Keys> void foo(int key) { SwitchGenerator<Keys...>::generate(key); }
这种方式生成的是if-else链,但编译器会对其做等价优化,效率和switch相差无几。
C++11及以上:初始化列表展开法
还可以利用数组初始化列表展开参数包,实现同样逻辑:
// 单个参数的处理函数 template<int Key> void case_handler(int key) { if (key == Key) { bar<Key>(); } } template<int... Keys> void foo(int key) { // 用初始化列表展开所有case_handler调用 int dummy[] = {0, (case_handler<Keys>(key), 0)...}; (void)dummy; // 避免未使用变量的编译警告 }
内容的提问来源于stack exchange,提问作者weineng
相关产品推荐
相关产品推荐

