编译时创建Key-Task映射:hana::make_map模板提升问题
嘿,我明白你现在在搞编译时的Key-Task键值对映射,想用序号当键,还得让这个序号直接作为对应Task类型的模板参数,用Boost.Hana来实现对吧?你提到要把Task提升为元函数,这个思路完全没问题,只是在适配Hana的元类型体系时容易踩坑,我来一步步帮你解决:
核心思路拆解
咱们的目标是构建编译时的常量序号(Key)→ 带对应序号模板参数的Task类型的映射,Hana的元编程体系里,模板类本身不能直接作为元函数使用,得先把它包装成Hana能识别的元函数对象,然后再构建映射表。
1. 先把Task包装成元函数
假设你的Task模板是这样的(根据你给出的代码片段补全):
template <std::size_t Key, typename T = double, template<typename...> class Complex = std::complex> struct Task { // 这里放你的Task实现,比如关联Key的业务逻辑 using value_type = T; using complex_t = Complex<T>; static constexpr std::size_t key_value = Key; };
Hana提供了hana::template_工具,可以直接把普通模板包装成元函数——这个元函数接受对应数量的元参数(比如编译时常量、类型元对象、模板元对象),然后返回实例化后的类型。咱们这么写:
#include <boost/hana.hpp> namespace hana = boost::hana; // 把Task模板包装成元函数,它会接受3个参数:size_t常量、类型、模板 constexpr auto task_meta = hana::template_<Task>;
如果想固定T和Complex这两个参数,只留Key作为变量,可以用Hana的柯里化工具hana::curry来简化:
// 柯里化后,task_meta_default只需要传入Key就能生成Task<Key, double, std::complex> constexpr auto task_meta_default = hana::curry<3>(task_meta) (hana::type_c<double>) // 固定T为double (hana::template_<std::complex>); // 固定Complex为std::complex
2. 构建编译时映射表
接下来咱们要创建Hana的hana::map,里面的键是hana::size_c<Key>(编译时的size_t常量),值是对应的Task类型的元表示(hana::type_c<Task<Key>>)。
手动创建少量键值对
如果只需要几个固定的Key,直接写就行:
constexpr auto task_map = hana::make_map( hana::make_pair(hana::size_c<0>, hana::type_c<Task<0>>), hana::make_pair(hana::size_c<1>, hana::type_c<Task<1, float>>), // 也可以自定义T hana::make_pair(hana::size_c<2>, hana::type_c<Task<2, double, std::complex>>) );
批量生成连续序号的映射
如果要生成从0到N的连续序号映射,用Hana的range+fold组合自动生成更高效:
// 生成0到3的序号(左闭右开,实际是0、1、2) constexpr auto key_range = hana::make_range(hana::size_c<0>, hana::size_c<3>); // 遍历range,把每个Key和对应Task插入到map里 constexpr auto task_map = hana::fold(key_range, hana::make_map(), [](auto current_map, auto key) { // 用之前的元函数生成Task类型,再转成hana::type_c auto task_type = hana::type_c<typename decltype(task_meta_default(key))::type>; return hana::insert(current_map, hana::make_pair(key, task_type)); });
3. 编译时查询映射
现在你可以在编译时通过Key快速查到对应的Task类型了:
// 查询Key=0对应的Task类型 using Task0Type = typename decltype(hana::at_key(task_map, hana::size_c<0>))::type; // 编译时验证类型是否正确 static_assert(std::is_same_v<Task0Type, Task<0>>, "Task type mismatch!");
常见坑点提示
- 一定要用C17或更高版本:Hana的很多constexpr特性依赖C17的编译时函数支持,老版本会报错。
- 区分
hana::type和hana::types:前者是单个类型的元包装,后者是类型元组,映射里的值应该用hana::type_c<T>,别误写成hana::types<T>。 - 模板参数数量要匹配:如果你的Task有3个模板参数,
hana::template_<Task>就必须接受3个元参数,少传或多传都会编译失败,用柯里化可以帮你固定部分参数。
内容的提问来源于stack exchange,提问作者Wum
相关产品推荐
相关产品推荐

