包含自身映射的 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::vectorstd::liststd::forward_list

如果您想使用std::map 并对其有标准保证,则需要在某个时候添加一级间接。

【讨论】:

std::map&lt;std::string, std::any&gt; 会是一个合适的额外间接级别吗? @Eljay 当然,但你不需要让它那么复杂。 std::map&lt;std::string, std::unique_ptr&lt;T&gt;&gt; 在 OP 的例子中就足够了。 std::unique_ptr 不需要它的类型是完整的。

以上是关于包含自身映射的 C++ 变体的主要内容,如果未能解决你的问题,请参考以下文章

在 ManyToMany 双向映射中,findAll() 获取行,每行包含其子项,而子项又包含其自身

c++ 类包含一个与自身类型相同的静态成员。为啥是这种模式?

c++数值61,韦伯分布,随机种子,

构造一个包含变体类型索引中第 n 个类型值的 boost 变体?

包含对其自身实例的引用的标准向量的模板类

如何在包含类型的变体上使用比较运算符?