如何利用std::integer_sequence创建std::initializer_list?
解决用
std::integer_sequence初始化std::map的问题 你需要利用std::integer_sequence生成std::map的初始化列表,但当前实现存在两个核心问题:
- 直接返回
std::initializer_list会导致悬空引用:initializer_list本身不存储数据,它指向的是函数内部临时数组的地址,函数返回后该数组会被销毁,引用随即失效。 - 让
constexpr函数直接返回std::map会报错:std::map不属于C++标准定义的字面类型,而constexpr函数的返回类型必须是字面类型(或void),因此不符合语法要求。
同时你需要将std::map作为类的私有成员,在成员初始化列表中完成初始化。
方案1:用编译期std::array传递初始化数据
std::array是字面类型,可以在constexpr函数中返回,且静态存储的数组生命周期贯穿程序全程,不会出现悬空问题。我们可以先生成编译期数组,再用数组的迭代器范围初始化std::map:
#include <map> #include <utility> #include <iostream> #include <array> // 生成编译期数组,每个元素是{索引, 0}的键值对 template<uint8_t... Indices> constexpr auto MakeInitArray(std::integer_sequence<uint8_t, Indices...>) { return std::array<std::pair<uint8_t, uint8_t>, sizeof...(Indices)>{{{Indices, 0}...}}; } class MyClass { private: // 静态编译期数组,存储初始化数据 static constexpr auto s_init_array = MakeInitArray(std::integer_sequence<uint8_t, 2, 4, 5, 7, 8, 10, 11, 13, 15>{}); std::map<uint8_t, uint8_t> m_reg_map; public: // 用数组的迭代器范围初始化map,在成员初始化列表完成 MyClass() : m_reg_map(s_init_array.begin(), s_init_array.end()) {} void printMap() const { std::cout << m_reg_map.size() << std::endl; for (const auto& pair : m_reg_map) { std::cout << static_cast<int>(pair.first) << " has value " << static_cast<int>(pair.second) << std::endl; } } }; int main() { MyClass obj; obj.printMap(); return 0; }
方案2:直接在构造函数中展开参数包(C++17及以上)
如果编译器支持C++17,可以将类模板化,直接在成员初始化列表中展开模板参数包,生成initializer_list,无需额外的constexpr函数:
#include <map> #include <utility> #include <iostream> // 用索引列表作为类模板参数 template<uint8_t... Indices> class MyClass { private: std::map<uint8_t, uint8_t> m_reg_map; public: // 直接在初始化列表中展开参数包,生成初始化列表 MyClass() : m_reg_map({{Indices, 0}...}) {} void printMap() const { std::cout << m_reg_map.size() << std::endl; for (const auto& pair : m_reg_map) { std::cout << static_cast<int>(pair.first) << " has value " << static_cast<int>(pair.second) << std::endl; } } }; int main() { // 实例化时传入索引序列 MyClass<2, 4, 5, 7, 8, 10, 11, 13, 15> obj; obj.printMap(); return 0; }
原问题的核心原因
std::initializer_list是轻量级包装,仅指向临时数组内存,函数返回后该内存被释放,导致引用悬空,触发未定义行为。std::map不属于字面类型,无法作为constexpr函数的返回值,这是C++标准对constexpr函数的强制约束。
内容的提问来源于stack exchange,提问作者maestro
相关产品推荐
相关产品推荐

