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

incomplete types with std::map and std::variant

考虑在 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<const int, recursive_tag>,因此无法在 gcc 7/8 上编译,而 std::pair<const int, recursive_tag> 本身失败,因为 recursive_tag 是一个不完整的类型。

但是,编译器错误调用堆栈中没有任何内容告诉我为什么 std::pair<const int, recursive_tag> 需要实例化。顶行是:

variant:252:48: required from ‘void std::__detail::__variant::__erased_dtor(_Variant&&) [with _Variant = const std::__detail::__variant::_Variant_storage<false, int, std::map<int, RecursiveVariant<int, std::map<int, recursive_tag, std::less<int>, std::allocator<std::pair<const int, recursive_tag> > > >, std::less<int>, std::allocator<std::pair<const int, RecursiveVariant<int, std::map<int, recursive_tag, std::less<int>, std::allocator<std::pair<const int, recursive_tag> > > > > > > >&; 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<int, recursive_tag>,但应该实例化的实际 map 类型是 map<int, RecursiveVariant<int, map<int, recursive_tag>>>... 这应该只需要实例化 pair<const int, RecursiveVariant<...>> .

只需使 recursive_tag 完整(即通过添加 {})即可解决问题。但是,是什么导致问题开始?

line at issue 调用

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

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