Writing a simple JSON library from scratch: a tour through modern C++
That<p><pre><code>  struct JSONValue {
    std::optional<std::string> string;
    std::optional<double> number;
    std::optional<bool> boolean;
    std::optional<std::vector<JSONValue>> array;
    std::optional<std::map<std::string, JSONValue>> object;
    JSONValueType type;
  };
</code></pre>
<i>really</i> ought to be a variant, that would simplify things a lot. It'd just be<p><pre><code>  struct JSONValue;
  using variant_type = 
    std::variant<
     std::string
   , double
   , bool
   , std::vector<JSONValue>
   , std::map<std::string, JSONValue>
  >;
  struct JSONValue : variant_type { 
    using variant::variant;
  };
</code></pre>
then instead of switches you'd do:<p><pre><code>  std::string_view print_type(const variant_type& jtt) {
    using namespace std::literals;
    struct {
      auto operator()(const std::string&) const noexcept { return "String"sv; }
      auto operator()(double) const noexcept { return "Number"sv; }
      auto operator()(bool) const noexcept { return "Bool"sv; }
      auto operator()(const std::vector<JSONValue>&) const noexcept { return "Array"sv; }
      auto operator()(const std::map<std::string, JSONValue>&) const noexcept { return "Dict"sv; }
      auto operator()(std::monostate) const noexcept { return "Null"sv; }
    } vis;
    return std::visit(vis, jtt);
  }
</code></pre>
which is much safer than switch/cases