如何通过编译期推导简化多模板参数的clientAPI实现?
解决模板参数与运行时字符串映射的调用问题
针对你提出的三个问题,以下是具体实现方案:
1. 编译期遍历映射生成实例,运行时匹配调用
核心思路是编译期生成所有coreFun的模板实例,将字符串参数组合与对应实例的函数指针绑定成查找表,运行时通过输入的字符串匹配后调用。
实现代码
#include <tuple> #include <array> #include <string_view> #include <stdexcept> // 原coreFun定义 template <int shoes, bool isNew, char color> int coreFun(int p1, int p2, int p3) { return shoes + isNew + int(color) + p1 + p2 + p3; } int clientAPI( auto&& shoes, auto&& isNew, auto&& color, int p1, int p2, int p3 ) { using namespace std; auto clientInputs = tuple(forward<decltype(shoes)>(shoes), forward<decltype(isNew)>(isNew), forward<decltype(color)>(color)); constexpr auto mapping = tuple( tuple(pair("sniker", 0), pair("leather", 1), pair("other", 2)), tuple(pair("no", false), pair("yes", true)), tuple(pair("red", 'r'), pair("green", 'g'), pair("blue", 'b')) ); // 编译期生成查找表:字符串组合 -> coreFun实例指针 constexpr auto create_lookup_table() { using FuncPtr = int(*)(int, int, int); constexpr size_t total = tuple_size_v<decltype(get<0>(mapping))> * tuple_size_v<decltype(get<1>(mapping))> * tuple_size_v<decltype(get<2>(mapping))>; array<pair<tuple<string_view, string_view, string_view>, FuncPtr>, total> table{}; size_t idx = 0; // 递归展开所有模板参数组合 [&]<std::size_t... SIs>(index_sequence<SIs...>) { ( [&]<std::size_t... NIs>(index_sequence<NIs...>) { ( [&]<std::size_t... CIs>(index_sequence<CIs...>) { ( [&]() { constexpr int s = get<SIs>(get<0>(mapping)).second; constexpr bool n = get<NIs>(get<1>(mapping)).second; constexpr char c = get<CIs>(get<2>(mapping)).second; table[idx++] = { {get<SIs>(get<0>(mapping)).first, get<NIs>(get<1>(mapping)).first, get<CIs>(get<2>(mapping)).first}, &coreFun<s, n, c> }; }() , ...); }(make_index_sequence<tuple_size_v<decltype(get<2>(mapping))>>{}) , ...); }(make_index_sequence<tuple_size_v<decltype(get<1>(mapping))>>{}) , ...); }(make_index_sequence<tuple_size_v<decltype(get<0>(mapping))>>{}); return table; } constexpr auto lookup_table = create_lookup_table(); // 构建输入键并查找调用 auto input_key = apply([](const auto&... input) { return make_tuple(string_view(input)...); }, clientInputs); for (const auto& entry : lookup_table) { if (entry.first == input_key) { return entry.second(p1, p2, p3); } } throw invalid_argument("Invalid input parameters"); }
2. 用std::function与运行时查找表实现
如果编译期生成函数指针数组受限(比如C++版本较低),可以用std::function包装实例,运行时初始化查找表(首次调用时构建,后续复用):
实现代码片段
int clientAPI( auto&& shoes, auto&& isNew, auto&& color, int p1, int p2, int p3 ) { using namespace std; auto clientInputs = tuple(forward<decltype(shoes)>(shoes), forward<decltype(isNew)>(isNew), forward<decltype(color)>(color)); constexpr auto mapping = tuple( tuple(pair("sniker", 0), pair("leather", 1), pair("other", 2)), tuple(pair("no", false), pair("yes", true)), tuple(pair("red", 'r'), pair("green", 'g'), pair("blue", 'b')) ); // 静态局部变量:首次调用时初始化查找表 static const auto lookup_table = []() { unordered_map<tuple<string_view, string_view, string_view>, function<int(int, int, int)>> table; [&]<std::size_t... SIs>(index_sequence<SIs...>) { ( [&]<std::size_t... NIs>(index_sequence<NIs...>) { ( [&]<std::size_t... CIs>(index_sequence<CIs...>) { ( [&]() { constexpr int s = get<SIs>(get<0>(mapping)).second; constexpr bool n = get<NIs>(get<1>(mapping)).second; constexpr char c = get<CIs>(get<2>(mapping)).second; table[{get<SIs>(get<0>(mapping)).first, get<NIs>(get<1>(mapping)).first, get<CIs>(get<2>(mapping)).first}] = [](int a, int b, int c_val) { return coreFun<s, n, c>(a, b, c_val); }; }() , ...); }(make_index_sequence<tuple_size_v<decltype(get<2>(mapping))>>{}) , ...); }(make_index_sequence<tuple_size_v<decltype(get<1>(mapping))>>{}) , ...); }(make_index_sequence<tuple_size_v<decltype(get<0>(mapping))>>{}); return table; }(); auto input_key = apply([](const auto&... input) { return make_tuple(string_view(input)...); }, clientInputs); auto it = lookup_table.find(input_key); if (it != lookup_table.end()) { return it->second(p1, p2, p3); } throw invalid_argument("Invalid input parameters"); }
3. 通用调度函数:适配任意数量模板参数
可以封装一个通用的dispatch函数,接收目标模板函数、输入tuple、映射tuple,自动处理映射与实例调用,无需针对每个场景重复编写逻辑:
通用实现代码
#include <tuple> #include <array> #include <string_view> #include <stdexcept> #include <utility> // 通用调度函数:适配任意数量的模板参数与映射 template <template <auto...> typename Func, typename InputTuple, typename MappingTuple, typename... Args> auto dispatch(const InputTuple& inputs, const MappingTuple& mappings, Args&&... args) { using namespace std; constexpr size_t map_count = tuple_size_v<MappingTuple>; using MapIndices = make_index_sequence<map_count>; // 编译期生成查找表 constexpr auto generate_lookup_table = []<std::size_t... MapIs>(index_sequence<MapIs...>) { using TemplateArgsTuple = decltype(make_tuple(get<0>(get<MapIs>(mappings)).second...)); using FuncPtr = decltype(&Func<std::get<MapIs>(TemplateArgsTuple{})...>); // 计算总组合数:各映射元素数量的乘积 constexpr size_t total = (tuple_size_v<decltype(get<MapIs>(mappings))> * ...); array<pair<tuple<string_view...>, FuncPtr>, total> table{}; size_t idx = 0; // 递归展开所有参数组合 auto expand = [&]<std::size_t... Is, typename... Ts>(index_sequence<Is...>, Ts... template_args) { if constexpr (sizeof...(Is) == map_count) { // 所有映射展开完成,添加条目 table[idx++] = { {get<Is>(get<MapIs>(mappings)).first...}, &Func<Ts...> }; } else { constexpr size_t current_map_idx = sizeof...(Is); using CurrentMap = decltype(get<current_map_idx>(mappings)); [&]<std::size_t... CurrIs>(index_sequence<CurrIs...>) { (expand(index_sequence<Is..., CurrIs>{}, template_args..., get<CurrIs>(get<current_map_idx>(mappings)).second), ...); }(make_index_sequence<tuple_size_v<CurrentMap>>{}); } }; expand(index_sequence<>{},); return table; }; constexpr auto lookup_table = generate_lookup_table(MapIndices{}); // 构建输入键 auto input_key = apply([](const auto&... input) { return make_tuple(string_view(input)...); }, inputs); // 查找并调用 for (const auto& entry : lookup_table) { if (entry.first == input_key) { return entry.second(forward<Args>(args)...); } } throw invalid_argument("Invalid input parameters"); } // 原coreFun定义 template <int shoes, bool isNew, char color> int coreFun(int p1, int p2, int p3) { return shoes + isNew + int(color) + p1 + p2 + p3; } // 简化后的clientAPI int clientAPI( auto&& shoes, auto&& isNew, auto&& color, int p1, int p2, int p3 ) { using namespace std; auto clientInputs = tuple(forward<decltype(shoes)>(shoes), forward<decltype(isNew)>(isNew), forward<decltype(color)>(color)); constexpr auto mapping = tuple( tuple(pair("sniker", 0), pair("leather", 1), pair("other", 2)), tuple(pair("no", false), pair("yes", true)), tuple(pair("red", 'r'), pair("green", 'g'), pair("blue", 'b')) ); return dispatch<coreFun>(clientInputs, mapping, p1, p2, p3); }
说明
这个通用dispatch函数支持任意数量的模板参数,只要映射tuple的每个元素是包含(字符串键,模板参数值)的pair tuple,就能自动生成所有可能的模板实例,并完成运行时匹配调用。
内容的提问来源于stack exchange,提问作者user2961927
相关产品推荐
相关产品推荐

