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

南笙酒味 提交于 2019-12-06 19:27:11

问题


Consider this simplified and very specific implementation of a recursive variant on top of 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; 
}

This fails to compile on gcc 7/8 due to trying to instantiate std::pair<const int, recursive_tag>, which itself fails because recursive_tag is an incomplete type.

But, nothing in the compiler error call-stack indicates to me why std::pair<const int, recursive_tag> needs to be instantiated. The top line there is:

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]

pointing to:

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

While type map<int, recursive_tag> is spelled in there, the actual map type that should be instantiated is map<int, RecursiveVariant<int, map<int, recursive_tag>>>... which should only necessitate the instantiation of pair<const int, RecursiveVariant<...>>.

Simply making recursive_tag complete (i.e. by adding {}) fixes the problem. But what causes the problem to begin with?


回答1:


The line at issue calls

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

The need to perform ADL for __get is sufficient to trigger instantiation of any and all associated classes of the type of __v, i.e., _Variant, to look for potential friend functions (and function templates) with that name defined within these classes. That includes the pair that tripped you up.



来源:https://stackoverflow.com/questions/50589231/incomplete-types-with-stdmap-and-stdvariant

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!