基本上我想要一些容器,类似于 std::unordered_map<std::string, std::variant<unsigned, /*self_type*/>>
.在此容器中,无符号值是终端节点,而 self_type
代表一棵子树,应该进一步搜索直到终端节点。
然而,这可以通过一个额外的包装类来实现。
struct node {
std::unordered_map<std::string,
std::variant<unsigned, std::unique_ptr<node>>> children;
};
很公平,但我想将其初始化为普通 std::unordered_map
带有嵌套的初始化器列表。例如:
{
{
"str1",
{
{"strstr1", 1},
{"strstr2", 2}
}
},
{"str2", 3}
}
也欢迎提出更合适的数据结构的建议。
最佳答案
解决方案 1 - 使用包装类:
struct node {
using myvar = boost::variant< unsigned, boost::recursive_wrapper< node > >;
using childmap = std::unordered_map< std::string, myvar >;
node() {}
node( std::initializer_list< childmap::value_type > il ) :
children( il ) {}
childmap children;
};
我在这里使用 boost::variant,因为我没有可用的 std::variant
。
boost::recursive_wrapper
是必需的,因为 boost::variant
通常需要一个完整的类型,但此时 node
仍然不完整。
boost::recursive_wrapper
没什么神奇的。它只是指针的包装器!正如我们所知,可以毫无问题地为不完整类型声明指针。这个包装类只是隐藏了一个事实,即通过处理分配、释放和提供值语义来使用指针。它有 boost::variant
的特殊支持,使包装器完全透明,因此可以像根本没有包装器类一样使用变体。
用法:
node n {
{ "foo", 1 },
{ "bar", 2 },
{ "baz", node {
{ "bim", 3 },
{ "bam", 4 }}
}
};
n.children[ "fum" ] = 5;
n.children[ "fup" ] = node{{ "fap", 6 }};
初始化列表中的显式“节点”是必需的,因为变体构造函数无法从嵌套的初始化列表中推断出类型。
演示:http://coliru.stacked-crooked.com/a/123c59a3523c39ed
解决方案 2 - 从 unordered_map 派生:
这消除了对“children”成员的需要。
struct nodemap :
std::unordered_map<
std::string,
boost::variant< unsigned, boost::recursive_wrapper< nodemap > > >
{
using base = std::unordered_map<
std::string,
boost::variant< unsigned, boost::recursive_wrapper< nodemap > > >;
// Forward all constructors of the base class.
using base::base;
};
用法:
nodemap n{
{ "foo", 1 },
{ "bar", 2 },
{ "baz", nodemap{
{ "bim", 3 },
{ "bam", 4 }}
}};
n[ "fum" ] = 5;
n[ "fup" ] = nodemap{{ "fap", 6 }};
更多使用示例:
// Add something to a child nodemap.
boost::get<nodemap>( n[ "baz" ] )[ "fap" ] = 7;
// This will throw a boost::bad_get exception because n[ "foo" ] is not a nodemap.
//boost::get<nodemap>( n[ "foo" ] )[ "fap" ] = 8;
// To avoid this problem, we can check if the child actually is a nodemap:
if( nodemap* pn = boost::get<nodemap>( &n[ "foo" ] ) )
{
(*pn)[ "fap" ] = 8;
}
关于c++ - 清除具有未知递归级别的嵌套关联容器的初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42451002/