考虑在 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 上编译,它本身就失败了,因为 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
完整(即通过添加 {}
)解决了问题。但问题的根源是什么?
最佳答案
std::_Destroy(std::__addressof(__get<_Np>(__v)));
对 __get
执行 ADL 的需要足以触发 __v
类型的任何和所有关联类的实例化,即 _Variant
,以查找在这些类中定义的具有该名称的潜在友元函数(和函数模板)。这包括让你绊倒的pair
。
关于c++ - 具有 std::map 和 std::variant 的不完整类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50589231/