具有 std::map 和 std::variant 的不完整类型

Posted

技术标签:

【中文标题】具有 std::map 和 std::variant 的不完整类型【英文标题】:incomplete types with std::map and std::variant 【发布时间】:2018-11-08 09:31:26 【问题描述】:

考虑在std::variant 之上递归变体的这种简化且非常具体的实现:

#include <map>
#include <variant>

struct recursive_tag;

template <typename...>
struct RecursiveVariant;

template <>
struct RecursiveVariant<int, std::map<int, recursive_tag>>
    : std::variant<int, std::map<int, RecursiveVariant<int, std::map<int, recursive_tag>>>>

    using underlying = std::variant<int,
          std::map<int, RecursiveVariant<int, std::map<int, recursive_tag>>>>;
    using underlying::underlying;
;


int main() 
    RecursiveVariant<int, std::map<int, recursive_tag>> rv; 

由于尝试实例化 std::pair&lt;const int, recursive_tag&gt; 而无法在 gcc 7/8 上编译,而这本身会失败,因为 recursive_tag 是不完整的类型。

但是,编译器错误调用堆栈中的任何内容都没有告诉我为什么 std::pair&lt;const int, recursive_tag&gt; 需要被实例化。最上面一行是:

variant:252:48: 需要来自‘void std::__detail::__variant::__erased_dtor(_Variant&amp;&amp;) [with _Variant = const std::__detail::__variant::_Variant_storage&lt;false, int, std::map&lt;int, RecursiveVariant&lt;int, std::map&lt;int, recursive_tag, std::less&lt;int&gt;, std::allocator&lt;std::pair&lt;const int, recursive_tag&gt; &gt; &gt; &gt;, std::less&lt;int&gt;, std::allocator&lt;std::pair&lt;const int, RecursiveVariant&lt;int, std::map&lt;int, recursive_tag, std::less&lt;int&gt;, std::allocator&lt;std::pair&lt;const int, recursive_tag&gt; &gt; &gt; &gt; &gt; &gt; &gt; &gt;&amp;; long unsigned int _Np = 0]

指向:

249   template<typename _Variant, size_t _Np>
250     void
251     __erased_dtor(_Variant&& __v)
252      std::_Destroy(std::__addressof(__get<_Np>(__v))); 

虽然在其中拼写了 map&lt;int, recursive_tag&gt; 类型,但应该实例化的实际 map 类型是 map&lt;int, RecursiveVariant&lt;int, map&lt;int, recursive_tag&gt;&gt;&gt;... 这应该只需要实例化 pair&lt;const int, RecursiveVariant&lt;...&gt;&gt;

只需使recursive_tag 完整(即通过添加)即可解决问题。但问题的根源是什么?

【问题讨论】:

【参考方案1】:

line at issue 来电

std::_Destroy(std::__addressof(__get<_Np>(__v)));

__get 执行ADL 的需要足以触发__v 类型的任何和所有关联类的实例化,即_Variant,以寻找潜在的朋友函数(和函数模板)在这些类中定义的名称。这包括让你绊倒的pair

【讨论】:

Argh,该文件中如何还有更多对该函数的不合格调用。我敢肯定新的会在一夜之间出现。

以上是关于具有 std::map 和 std::variant 的不完整类型的主要内容,如果未能解决你的问题,请参考以下文章

从具有自定义类型的 c++ 中的 std::map 获取值

带有键的 std::map 作为具有三个 int 成员的结构 [重复]

C++ 将预先保留的哈希映射(std::unordered_map)与整数键和连续数据数组(std::vector)进行比较

std::Map

std::map 糟糕的字符仅在发布模式下

具有私有构造函数的 unordered_map 值类型