如何通过大括号初始化递归式std::unordered_map及树形结构Tree
问题描述
需要实现一个树形结构类型,支持两种方式的大括号初始化:
Tree t1 = 1; // 单个值初始化 Tree t2 = {{"a",t1},{"b",{{"x",2},{"y",4}}},{"c",5}}; // 嵌套键值对初始化
最初尝试继承std::unordered_map,并用unique_ptr包装递归的Tree对象,但无法正确编写初始化列表构造函数,代码如下:
// 原错误实现 using std; struct Tree : unordered_map<string, unique_ptr<Tree>>{ int simple; Tree() = default; Tree(unsigned s): simple{s}{}; Tree(const initializer_list<pair<string, unique_ptr<Tree>>> & il): simple{s} { // 编译失败,且指针类型无法匹配用户期望的初始化写法 } };
另有一个基于vector的可行实现作为参考:
struct TreeV : vector<pair<string, TreeV>>{ TreeV(const vector<pair<string, TreeV>> & v) : vector<pair<string, TreeV>>(v){}; }; vector<pair<string, TreeV>> t3 = {{"a",t1},{"b",{{"x",2},{"y",4}}},{"c",5}};
需要解决的核心问题:如何让继承自std::unordered_map的递归Tree类型支持用户期望的嵌套大括号初始化语法?
解决方案
核心思路是调整构造函数的参数类型,让其匹配用户的初始化写法,同时在内部处理Tree对象到unique_ptr<Tree>的转换。具体实现如下:
#include <unordered_map> #include <string> #include <memory> using namespace std; struct Tree : unordered_map<string, unique_ptr<Tree>> { int simple; // 默认构造函数,初始化simple为0 Tree() : simple(0) {} // 单个int值初始化 Tree(int s) : simple(s) {} // 接受嵌套大括号的初始化列表构造函数 Tree(initializer_list<pair<string, Tree>> il) : simple(0) { for (auto&& entry : il) { // 将传入的Tree对象转移为unique_ptr,插入到map中 emplace(entry.first, make_unique<Tree>(move(entry.second))); } } // 支持赋值运算符接收初始化列表 Tree& operator=(initializer_list<pair<string, Tree>> il) { clear(); simple = 0; for (auto&& entry : il) { emplace(entry.first, make_unique<Tree>(move(entry.second))); } return *this; } };
关键说明
- 构造函数参数匹配:将初始化列表参数改为
initializer_list<pair<string, Tree>>,完全匹配用户{"key", Tree对象}的写法,避免了直接使用unique_ptr带来的类型不兼容问题。 - 内部指针转换:在构造函数中,通过
std::make_unique和std::move将传入的Tree对象转移为unique_ptr<Tree>,既保证了内存安全,又符合unordered_map的存储需求。 - 嵌套初始化支持:嵌套的
{{"x",2},{"y",4}}会自动调用Tree的初始化列表构造函数生成一个子Tree对象,再被外层构造函数处理为指针插入到父节点中,完美支持递归嵌套语法。 - 赋值运算符补充:重载赋值运算符,让
Tree对象可以直接被初始化列表赋值,进一步贴合用户的使用习惯。
验证代码
使用用户期望的写法测试:
int main() { Tree t1 = 1; Tree t2 = {{"a", t1}, {"b", {{"x", 2}, {"y", 4}}}, {"c", 5}}; // 验证结构:t2["a"]指向t1的副本,t2["b"]包含两个子节点,t2["c"]指向值为5的Tree return 0; }
内容的提问来源于stack exchange,提问作者danculo
相关产品推荐
相关产品推荐

