如何在 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
.
的指针
我必须用 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
.