【问题标题】:How to implement Javascript-like dynamic typing in C++如何在 C++ 中实现类 Javascript 的动态类型
【发布时间】:2020-08-25 07:58:41
【问题描述】:

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

我想采用接近以下示例的方法。我正在用某种伪代码写我的想法,基于TypeScript Syntax

我正在对一个表示 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

【问题讨论】:

  • 您可以尝试使用旧版本的github.com/open-source-parsers/jsoncpp,甚至可以使用github.com/kgabis/parson 使用C 风格。
  • std::variant 可以解决您的问题,但它是 C++17。也许你可以让你的编译器使用它,或者查看它的实现。但说真的,如果您的编译器足够老,不支持 C++11,请更新您的编译器。
  • 您的环境似乎是最新的,您确定您使用的是正确的编译器标志(例如 --std=c++11 或 --std==c++17 )... ?
  • @bitmask 这里有一个用于 pre c++17 编译器的仅标头变体:github.com/mpark/variant。根据我的经验,它运作良好。
  • 根据这个网站,你的clang增强编译器支持c++11:community.idera.com/developer-tools/b/blog/posts/…你的编译器版本是多少?你能用bcc32x --version 或类似的东西检查一下吗?

标签: c++ json dynamic-typing


【解决方案1】:

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

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

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

如果您使用的是 C++17,则可以使用std::variant,它本质上是一个类型安全的union。在 C++17 之前(在您的情况下),可以使用 boost::variant 代替。

【讨论】:

  • 有一个额外的步骤来解决:递归(天真的方式是union JSonValue { /*..*/ std::map&lt;string, JSonValue&gt; dict; std::vector&lt;JSonValue&gt; arr; };)。
【解决方案2】:

只需查看源代码即可获得一些灵感。例如here,你可以看到 Niels 是如何解决这个问题的:他定义了一个联合 json_value,由几个指向特定可能类型的指针组成。然后将json_value 对象的具体类型存储在定义为herevalue_t 类型的单独值中。

重要提示:如果您的编译器不支持 C++11,则不允许联合包含非平凡成员。从那以后,它就不能包含 std::string,而只能包含指向 std::string 的指针。

【讨论】:

    【解决方案3】:

    如果我正确理解您的问题,您需要类似工会的东西。我推荐std::variant(或boost::variant,如果编译器不支持C++17)。

    【讨论】:

    • 有一个额外的步骤来解决:递归(天真的方式是union JSonValue { /*..*/ std::map&lt;string, JSonValue&gt; dict; std::vector&lt;JSonValue&gt; arr; };
    猜你喜欢
    • 2012-04-16
    • 1970-01-01
    • 2017-03-30
    • 2018-11-28
    • 1970-01-01
    • 2021-05-12
    • 1970-01-01
    • 2015-02-21
    • 2017-07-11
    相关资源
    最近更新 更多