C++17中如何展开类型与整数值的多个模板参数包?
C++17中通过模板参数实现类型-整数映射并自动生成operator=是否可行?
需求背景
此前已实现将类型映射到整数值并赋值给type_的硬编码方案,现需改为通过模板参数传入类型集合与对应整数值,自动生成operator=的特化逻辑,替代硬编码。尝试让MyStructure继承带类型和整数参数包的基类时,触发编译错误:
'Types': 如果类模板包含模板参数包,其必须位于模板参数列表的末尾
原问题伪代码
struct MyStructure { std::array<std::pair<TYPE, int>> map { { int, 1 }, { char, 2 }, { double, 4 }, { std::string, 8 } }; template <typename T> auto operator=(const T &arg) { // 根据arg的类型,将对应整数值写入成员变量type_ } int type_ = 0; }; int main() { MyStructure myStruct; myStruct = 1; // 应将1存入type_ myStruct = "Hello world"; // 应将8存入type_ }
尝试的基类实现(触发错误)
template<typename... Types, int...ints> class Base_Type { // 尝试展开参数包生成特化 }; template<typename... Types, int...ints> struct MyStructure : Base_Type<Types..., ints...> { template <typename T> auto operator=(const T &arg) { // 检查T是否在Types中 // 查询Base_Type的T特化获取对应整数值并写入type_ } int type_ = 0; };
解答:需求完全可行,修正方案如下
C++模板规则确实不允许类模板同时存在两个独立的参数包(如typename... Types和int...ints),因为编译器无法区分两个包的边界。但我们可以通过将类型与对应整数配对,用单个参数包传递所有映射关系的方式解决问题。
实现步骤
- 定义单个类型-整数映射的辅助基类
#include <type_traits> #include <tuple> #include <utility> #include <string> // 封装单个类型与整数的映射关系 template<typename T, int Val> struct TypeToIntMapping { static constexpr int value = Val; using type = T; };
- 实现聚合映射的基类
继承所有传入的TypeToIntMapping实例,提供类型查找与数值获取的逻辑:
// 聚合所有映射关系的基类 template<typename... Mappings> struct TypeMapBase : Mappings... { // 查找对应类型的映射数值 template<typename T> static constexpr int get_value() { return get_value_impl<T>(std::index_sequence_for<Mappings...>{}); } private: // 利用索引序列遍历所有映射,匹配类型并返回对应数值 template<typename T, size_t... Idx> static constexpr int get_value_impl(std::index_sequence<Idx...>) { return (... + (std::is_same_v<T, typename std::tuple_element_t<Idx, std::tuple<Mappings...>>::type> ? std::tuple_element_t<Idx, std::tuple<Mappings...>>::value : 0)); } };
- 实现MyStructure类
继承TypeMapBase,并实现operator=:
template<typename... Mappings> struct MyStructure : TypeMapBase<Mappings...> { template<typename T> auto operator=(const T& arg) { // 编译期检查类型是否在映射列表中 static_assert((std::is_same_v<T, typename Mappings::type> || ...), "类型不在映射列表中"); type_ = this->template get_value<T>(); } int type_ = 0; };
使用示例
// 定义别名简化映射写法 template<typename T, int Val> using MapPair = TypeToIntMapping<T, Val>; int main() { // 传入类型-整数的映射集合 using MyStruct = MyStructure< MapPair<int, 1>, MapPair<char, 2>, MapPair<double, 4>, MapPair<std::string, 8> >; MyStruct myStruct; myStruct = 1; // type_ = 1 myStruct = std::string("Hello world"); // type_ = 8 // myStruct = true; // 触发编译错误:类型不在映射列表中 }
内容的提问来源于stack exchange,提问作者Wad
相关产品推荐
相关产品推荐

