包含自身映射的 C++ 变体
Posted
技术标签:
【中文标题】包含自身映射的 C++ 变体【英文标题】:C++ variant containing a map of itself 【发布时间】:2021-12-29 13:45:14 【问题描述】:我希望能够创建一个包含std::map<std::string, MyVariant>
作为其案例之一的变体。理想的情况是能够写出类似的东西
using MyVariant = std::variant<int, std::string, std::map<std::string, MyVariant>>;
但这需要前向声明。
我知道以前有人问过类似的问题,例如here 和 here,但这些主要集中在 std::vector
的情况下,并且由于 C++17 允许 std::vector
使用不完整类型,而 std::map
不允许使用。
特别是,我想知道this answer 中的定点组合器解决方案是否适用于这种情况?根据该答案改编代码:
#include <map>
#include <string>
#include <variant>
// non-recursive definition
template<typename T>
using VariantImpl = std::variant<int, std::string, std::map<std::string, T>>;
// fixed-point combinator
template<template<typename> typename K>
struct FixCombinator : K<FixCombinator<K>>
using K<FixCombinator>::K;
;
using MyVariant = FixCombinator<VariantImpl>;
但是,如果有其他方法可以做到这一点,我也会对此感兴趣。
【问题讨论】:
你用的是什么编译器? this compiles @KamilCuk - 我想避免未定义的行为。不幸的是,在某些编译器上成功编译并不能保证这一点。 【参考方案1】:这是不可能的(至少通过标准保证),因为std::variant
要求使用的类型是完整的,而std::map
要求键和值类型在实例化时是完整的类型。但是你的构造只有在实例化之后才会完成。
唯一允许这种递归构造(至少在某种程度上)的标准容器是std::vector
、std::list
和std::forward_list
。
如果您想使用std::map
并对其有标准保证,则需要在某个时候添加一级间接。
【讨论】:
std::map<std::string, std::any>
会是一个合适的额外间接级别吗?
@Eljay 当然,但你不需要让它那么复杂。 std::map<std::string, std::unique_ptr<T>>
在 OP 的例子中就足够了。 std::unique_ptr
不需要它的类型是完整的。以上是关于包含自身映射的 C++ 变体的主要内容,如果未能解决你的问题,请参考以下文章
在 ManyToMany 双向映射中,findAll() 获取行,每行包含其子项,而子项又包含其自身
c++ 类包含一个与自身类型相同的静态成员。为啥是这种模式?