Simple C++11 friendly header-only bindings to Lua
A component of PM-Game-Server.
Reference to Selene and fix some features to meet the PM-Game-Server's requirements
- cmake 2.8+(可选, 如果不编译测试用例就不用)
- lua 5.2+
- 一个支持C++14的编译器(最好不要是clang, 因为用它过不了测试用例, 推荐gcc)
nua::Context ctx;
如果不需要打开lua标准库:
nua::Context ctx{false};
当nua::Context析构时, 所有其关联的资源都会被回收(包括通过值传入的C++对象)
ctx.load("path/to/your.lua");
ctx(R"(print("hello, world"))");
ctx["foo"] = []{ std::cout << "hello, nua" << std::endl; }; /**< lambda */
ctx["bar"] = std::function<...>(...); /**< stl function */
ctx["barz"] = std::bind(...);
struct T
{
type operator()(...)
{
...
}
} callable;
ctx["func"] = callable; /**< callable object */
之后你可以在lua中调用这些函数
ctx["foo"](); /**< 没有返回值和参数 */
ctx["bar"](1, 2, "hello").get<int>(); /**< 获取int返回值 */
int x;
std::string y;
std::tie(x, y) = ctx["barz"](1, 2, 3).get<int, std::string>(); /**< 接收多返回值 */
struct T
{
int v;
int func(int y);
};
ctx.setClass<T>("v", &T::v, "func", &T::func);
然后可以在lua中这样访问这个类:
function bar(t)
print(t:v()) --访问T::v
t:set_v(123) --设置T::v
t:func(123) --调用T::func
end
当然, t需要由C++传给lua:
T t;
ctx["bar"](t);
通过setClass向nua注册过的类都可以传递引用
struct T
{
T(const T&) = delete;
} t;
ctx["foo"](std::ref(t));
ctx["bar"](std::cref(t)); /**< 当传递const ref时不会生成相应的set_xxx, 同时非const成员函数也会无效 */
ctx["foo"] = [&]() -> const T& { return t; };
-- test.lua
function add(a, b)
return a + b
end
function pass_add(x, y)
return take_fun_arg(add, x, y)
end
nua::Context ctx;
ctx["take_fun_arg"] = [](nua::function<int(int, int)> func, int a, int b)
{
return func(a, b);
};
ctx.load("test.lua");
assert(ctx["pass_add"](3, 5) == 8);
nua::Context ctx;
struct B
{
virtual void apply() const
{
std::cout << "apply B" << std::endl;
}
};
struct T : B
{
void apply() const override
{
std::cout << "apply T" << std::endl;
}
};
ctx.setClass<B>("apply", &B::apply);
T t;
B& rt = t;
ctx(R"(
function apply(b)
b:apply()
end
)");
ctx["apply"](std::cref(rt));
- 基本类型的对象的引用不能传递给nua, 也不能在传递给nua的函数中作为返回值(仅const引用可以作为参数), 也不能从lua返回, 基本类型包括所有的数字类型, std::string, std::nullptr_t, nua::function
ctx(R"(
function foo(x)
end
)");
int x = 0;
ctx["foo"](x); /**< 合法 */
ctx["foo"](std::ref(x)); /**< 非法 */
ctx["foo"](std::cref(x)); /**< 非法 */
另外, 注意到std::string也是基本类型:
ctx["foo"] = [](const std::string& s) {...}; /**< 合法, 接收基础类型的const引用 */
ctx["foo"] = []() -> const std::string& {...}; /**< 非法, 试图返回基础类型的引用 */
- 以reference传入nua的对象才可以以reference的形式返回C++, 并且要保证const修饰正确
struct T
{
};
ctx.setClass<T>();
ctx(R"(
function forward_ref(x)
return x
end
)");
T t;
ctx["forward_ref"](t).get<const T&>(); /**< 非法, 要求返回t的reference但是传入时不是引用 */
ctx["forward_ref"](t).get<T&>(); /**< 非法, 要求返回t的reference但是传入时不是引用 */
ctx["forward_ref"](std::ref(t)).get<const T&>(); /**< 合法 */
ctx["forward_ref"](std::cref(t)).get<const T&>(); /**< 合法 */
ctx["forward_ref"](std::cref(t)).get<T&>(); /**< 非法, 不能从const reference转到reference */