Reputation:
I would like to be able to create a variant that contains a std::map<std::string, MyVariant>
as one of its cases. The ideal would be able to write something like
using MyVariant = std::variant<int, std::string, std::map<std::string, MyVariant>>;
but this requires forward declaration.
I'm aware that similar questions have been asked previously, e.g. here and here, but these have mainly been focused on the case of std::vector
, and since C++17 std::vector
is allowed to use incomplete types, while std::map
does not.
In particular, I'm wondering if the fixed-point combinator solution in this answer would work in this case? Adapting the code from that answer:
#include <map>
#include <string>
#include <variant>
// non-recursive definition
template<typename T>
using VariantImpl = std::variant<int, std::string, std::map<std::string, T>>;
// fixed-point combinator
template<template<typename> typename K>
struct FixCombinator : K<FixCombinator<K>>
{
using K<FixCombinator>::K;
};
using MyVariant = FixCombinator<VariantImpl>;
However if there's another way to do it, I would be interested with that also.
Upvotes: 2
Views: 1009
Reputation: 76658
This is not possible (at least by standard guarantees), since std::variant
requires the used types to be complete and std::map
requires key and value type to be complete types at the point of instantiation. But your construction will be complete only after it's instantiation.
The only standard containers allowing such a recursive construction (at least to some degree) are std::vector
, std::list
and std::forward_list
.
If you want to use std::map
and have standard guarantees for it, you need to add one level of indirection at some point.
Upvotes: 4