UDLua
https://zhuanlan.zhihu.com/p/356694688
Lua 只有“贫瘠”的 oop,利用元表实现,功能满满但十分原始。我来试着改善这个体验。
我前段时间写了一篇关于 C++ 动态反射库的文章
https://zhuanlan.zhihu.com/p/337200770
实际上,我这个动态库,设计已经出色到可以轻松成为一个跨语言的类型框架。
本文就来演示一下 Lua 装配上 C++ OOP 后可以多神奇!
项目地址:
https://github.com/Ubpa/UDLua
How to use
the example code is here
Suppose you need to use struct vec
struct vec {
float x;
float y;
float norm() const { return std::sqrt(x * x + y * y); }
};
Manual registration on Lua
if you want to do it on C++, check out this link ->.
local vec = UDRefl.RegisterType({
type = "vec",
fields = {
{ type = "float32", name = "x" },
{ type = "float32", name = "y" },
},
methods = {
{
name = "norm",
result = "float32",
body = function (p)
return math.sqrt(UDRefl.unbox(p.x * p.x + p.y * p.y))
end
}
}
})
Iterate over members
for iter in ObjectView.new(vec):GetFields():__range() do
local name, info = iter:__indirection():__tuple_bind()
print(name:GetView())
end
for iter in ObjectView.new(vec):GetMethods():__range() do
local name, info = iter:__indirection():__tuple_bind()
print(name:GetView())
end
Constructing types
v = SharedObject.new(vec)
print(v:GetType():GetName()) -- prints "vec"
Set/get variables
v.x = 3
v.y = 4
print("x: " .. v.x) -- prints "3"
Invoke Methods
print("norm: " .. v:norm()) -- prints "5"
Iterate over varables
for iter in v:GetTypeFieldVars():__range() do
local name, var = iter:__indirection():__tuple_bind()
print(name:GetView() .. ": ".. var)
end
Compiler compatibility
- Clang/LLVM >= 10.0
- GCC >= 10.0
- MSVC >= 1926
Tested platforms:
Windows 10: VS2019 16.8.5
Ubuntu 20: GCC 10.2, Clang 11.0
MacOS 11.0 : GCC 10.2
AppleClang 12 and Clang 11 is not supported
0x02. 设计思路
步骤如下
- 开发一套世界最强的 C++ 动态反射库 UDRefl
- 将 UDRefl 中的接口完全注册到其自身中,实现自举
- 在 lua 中注册 UDRefl,从而 lua 可以借助 UDRefl 操作其上已注册的类型
这里 UDRefl 扮演的角色是公共类型架构,以 C++ 的 OOP 作为主要参考对象,从而类型架构的性能与能力都充分好。
而 Lua 只是对接该公共类型架构的一个示例。日后还可以对接 C#,python 等。
0x03. 类型
一个类型由类名,基类列表,域,方法以及相应属性而组成。
类名支持类型系统,基于 C++,支持 const,&,&&。举例说,当你注册了 vec
类型,你可以使用 const{vec}
,从而禁止成员变量修改。
类名的细节请参考 C++ 生成式的编译期类型名
对象的空间设计成连续的,与 C/C++ 一致,根据基类和域的大小与对齐就可以自动算出基类偏移和域偏移。
方法分成员variable
函数,成员const
函数,静态函数。其中成员函数会将首个参数设置成 this
。对于特殊的函数(构造,析构,运算符等),用户可将其命名成meta函数名(__ctor
,__dtor
,__add
,__mul
等),当在 lua 使用 SharedObject.new
,运算符时,会去调用这些函数。
0x04. 域
在 C++ 中使用 UDRefl 时,获取域的方式为 v.Var("x")
,而在 Lua 中就十分自然,可直接写成 v.x
。
需要特别注意的是 Lua 中的对对象本身的赋值没法用元表重定义(但对对象成员的赋值是可以重定义的),所以我设计了特殊的域名 self
用来获取它本身,示例为 v.self = w
。
0x05. 方法
在 C++ 中使用 UDRefl 时,方法调用的方式为 v.Invoke("norm")
,而在 Lua 中就十分自然,可直接写成 v:norm()
。
类型定义中,使用类型数组 params
来声明参数类型。函数调用时,支持参数的自动类型转换,只要形参类型存在实参类型的构造函数即可,并且支持 &/&& 的各种转换(如 int
-> int&&
)。
另外还支持泛型参数,就像 C++ 的模板一样。即,当参数类型为 Ubpa::UDRefl::ObjectView
时,UDRefl 就将其视为泛型。
支持成员函数,这时第一个参数就是 this
。
0x06. 属性
属性 Attribute 同于 C# 的 Attribute,也就是挂在域,方法和类型上的对象。属性的类型完全可以是用户自定义的类型,并且支持任意的初始化。
============= End