如何在 C++ 中实现类似 Javascript 的动态类型

How to implement Javascript-like dynamic typing in C++

我必须用 C++ 写一个非常基础的 JSON serializer/deserializer。目标是构建类似于 https://github.com/nlohmann/json 的东西。不幸的是我不能使用这个很棒的库,因为我的编译器不完全支持 C++ 11 标准。切换编译器不是一个选项。

我想采用接近以下示例的方法。我正在根据 TypeScript Syntax.

用某种伪代码写我的想法

我正在成像一个 class 代表一个 JSON 对象,具有访问它的键并从中获取一些动态值的函数。

type JSONValue = int | double | string | list | JSONObject | ...;

class JSONObject {
  private map: Map<string, JSONValue>;

  public set(key: string, value: JSONValue) { ... };
  public get(key: string): JSONValue { ... };
  public stringify(): string;
}

我觉得大概的概念应该清楚了。解析 JSON 字符串不是问题。创建 JSON 字符串也很简单。但是在 C++ 中创建像 JSONValue 这样的类型是我无法理解的事情。

可能要走的路是模板,但我需要一些关于如何实现这种“动态”类型的指导。我想得到一些关于如何解决这个问题的例子。

编辑: 代码必须在带有 Clang 增强编译器的 RAD Studio 10.2.3 中运行。很难说这个编译器支持什么,所以我会测试每一个建议,并在出现问题时添加限制。

编辑 2: 运行 bcc32x --version 产生以下结果:

Embarcadero C++ 7.30 for Win32 Copyright (c) 2012-2017 Embarcadero Technologies, Inc.
Embarcadero Technologies Inc. bcc32x version 3.3.1 (36355.e71d049.f8c4cf9) (based on LLVM 3.3.1)
Target: i686-pc-win32-omf
Thread model: posix

如果我正确理解你的问题,你需要像工会这样的东西。如果编译器不支持 C++17,我推荐 std::variant (or boost::variant

在您的情况下,您实际上不需要完全动态类型化,因为 JSONValue 不能有任何类型,只有一些不同的类型。这就是您将 union 用于:

union JSONValue {
    long long integer;
    double floating;
    std::string string;
    ...
}

然而,non-trivially 可破坏类型的联合非常不安全,因为如果 string 是活动成员,您需要确保调用 string 的析构函数。

如果您使用的是 C++17,则可以使用 std::variant, which is essentially a type-safe union. Before C++17 (in your case), boost::variant

只需查看源代码即可获得一些灵感。例如 here you can see how Niels solved that problem: He defines a union json_value consisting of several pointers to the specific possible types. The concrete type of an json_value object is then stored in a separate value of type value_t defined here.

重要提示: 如果您的编译器不支持 C++11,则联合不允许包含 non-trivial 成员。从那以后,它不能包含 std::string 只有指向 std::string.

的指针