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?