一、互调原理

C++接入Lua,免不了互相调用的问题。互调的本质,其实就是数据传送。而这两种语言之间的数据类型是千差万别,而且内存管理机制也完全不同,C++有栈、堆内存,而Lua则是自动回收机制,如何保证数据传送呢?Lua虚拟机提供了一个栈结构,C++和Lua都可以往这个栈里压栈数据,栈负责数据类型的转换,同时保证压栈的数据在弹栈之前一直有效。

C调用Lua

  1. // **********************************
  2. // C++ 执行一个Lua(全局)函数
  3. // **********************************
  4. #include "lua.h"
  5. const char* LUA_CODE = NULL;
  6. void main()
  7. {
  8. lua_State* state = lua_newstate(); // lua全局环境表
  9. luaL_dostring(state, LUA_CODE); // 执行一段lua代码,定义了一个globalFunc
  10. lua_getglobal(state, "globalFunc"); // 将全局变量globalFunc的值压栈
  11. lua_pushstring(state, "motherfucker"); // C++这边将一个char*字符串压栈
  12. int errCode = lua_call(state, 1, 0); // 执行lua代码;globalFunc('motherfucker')
  13. }
  14. // 在lua的全局环境中定义一个全局函数globalFunc
  15. LUA_CODE = " \
  16. function globalFunc( str ) \
  17. print(str) \
  18. end \
  19. ";

Lua调用C

  1. // ****************************************
  2. // C++提供一个shit函数供Lua调用
  3. // ****************************************
  4. #include "lua.h"
  5. // ***************************************************
  6. // shit是提供给Lua调用的C函数,signature比如如下:
  7. // 1、必须返回int,返回值的意义是指执行这个C函数之后的压栈结果数,可以认为是返回值个数
  8. // Lua是要根据这个值来从栈中弹栈返回值的,如果数值错误,将导致栈状态被破坏。
  9. // 2、参数必须是有且仅有一个luaState*,表示C与Lua通过这个获取栈。
  10. // ***************************************************
  11. int shit(lua_State* state)
  12. {
  13. // 当执行这里的时候,lua栈已经压栈好了lua传来的数据,C这边只需要弹栈即可获取参数
  14. int param1 = static_cast<int>(lua_tointeger(state, -2)); // 栈顶-1参数,lua传来的第一个int
  15. int param2 = static_cast<int>(lua_tointeger(state, -1)); // 栈顶参数,lua出来的第二个int
  16. lua_pop(state, 2); // 弹栈栈顶两个参数
  17. // 将两个值相加,然后压栈,就是给lua的返回值
  18. lua_pushinteger(state, static_cast<LUA_INTEGER>( param1 + param2));
  19. return 1; // 告诉lua,我执行完了之后,栈里面剩一个返回值,你可以去取。
  20. }
  21. void main()
  22. {
  23. lua_State* state = lua_newstate(); // lua全局环境表
  24. lua_pushcfunction(state, shit);
  25. lua_setglobal(state, "globalshit"); // lua代码:globalshit = shit(C函数)
  26. }
  27. // ****************************************
  28. // Lua代码
  29. // ****************************************
  30. local fuck = globalshit
  31. // 虽然lua可以像下面这样随意调用fuck,但是一定要根据C函数shit的定义逻辑看,
  32. // 可以接受哪些参数。
  33. int result = fuck(1) // 报错
  34. int result = fuck(2,3) // 运行正常,result = 5
  35. int result = fuck(3,3,4) // 报错
  36. int result = fuck("3","3","4") // 报错

二、太麻烦了

我们可以看到,如果直接用lua本身提供的库函数,那么互调成本和门槛会非常高,写的代码很多,很容易出现压栈弹栈错误(这会破坏栈数据),同时还要对错误情况进行处理,上面的代码完全没有考虑参数不合法或者数量不对的情况。
因此我们完全有这个必要,对Lua/C/C++的互调进行封装,幸运的是,已经有前辈做了这个工作,并且一直在维护。

三、LuaBridge

LuaBridge是一个轻量级且无依赖的库,用于在C ++和Lua之间来回映射数据、函数和类。
LuaBridge支持在Lua5.1.0及以后的版本中使用,也兼容LuaJIT。

LuaBridge源码全部都是header files,#include就可以引入项目中,没有任何其他第三方项目依赖,不需要进行配置,使用也非常简单方便,遵循MIT许可,无限制使用。

1、namespace

namespace并不是指C++的namespace,其实就是Lua的table,设计目的就是为了逻辑分组,避免全局变量名污染。

  1. lua_State *L = stack->getLuaState();
  2. luabridge::getGlobalNamespace( L ) // 获取_G全局表
  3. .beginNamespace( "test" ) // 在_G打开或者创建test表
  4. .beginNamespace( "detail" ) // 打开或者创建test.detail表
  5. .endNamespace() // 关闭,表示不往里加元素了
  6. .beginNamespace( "utility" ) // 打开或者创建test.utility
  7. .endNamespace()
  8. .beginNamespace( "utility" ) // 添加相同的
  9. .endNamespace()
  10. .endNamespace();

给namespace添加元素:

  1. int globalVar;
  2. static float staticVar;
  3. std::string stringProperty;
  4. std::string getString( ) { return stringProperty; }
  5. void setString( std::string s ) { stringProperty = s; }
  6. int foo ( ) { return 42; }
  7. void bar ( char const * ) { }
  8. int cFunc ( lua_State *L ) { return 0; }
  9. void fuck( lua_State *L )
  10. {
  11. luabridge::getGlobalNamespace( L )
  12. .beginNamespace( "test" ) // test -- a namespace
  13. // 给test表添加属性
  14. .addProperty( "var1", &globalVar ) // test.var1 -- a lua_Number property
  15. .addProperty( "var2", &staticVar, false ) // test.var2 -- a read - only lua_Number property
  16. .addProperty( "prop1", getString, setString ) // test.prop1 -- a lua_String property
  17. .addProperty( "prop2", getString ) // test.prop2 -- a read - only lua_String property
  18. // 给test表添加C函数,这个C函数的格式不再有什么限制,随意返回值,随意的参数个数,参数类型(自定义类型必须注册给Lua)
  19. // 如果C函数需要访问lua_State,只需要确保这个lua_State是最后一个参数就可以了,方便的很。
  20. .addFunction( "foo", foo ) // test.foo -- a function returning a lua_Number
  21. .addFunction( "bar", bar ) // test.bar -- a function taking a lua_String as a parameter
  22. .addFunction( "cfunc", cFunc ) // test.cfunc -- a function with a variable argument list and multi - return
  23. .endNamespace();
  24. // test.var1 = 5 -- okay
  25. // test.var2 = 6 -- error: var2 is not writable
  26. // test.prop1 = "Hello" -- okay
  27. // test.prop1 = 68 -- okay, Lua converts the number to a string
  28. // test.prop2 = "bar" -- error : prop2 is not writable
  29. // test.foo() -- calls foo and discards the return value
  30. // test.var1 = foo() -- calls foo and stores the result in var1
  31. // test.bar( "Employee" ) -- calls bar with a string
  32. // test.bar( test ) -- error : bar expects a string not a table
  33. }

LuaBridge不会支持函数重载,以后也不会。

2、Lua调用C++(注册C++类)

  1. void fuck( lua_State *L )
  2. {
  3. luabridge::getGlobalNamespace( L )
  4. .beginNamespace( "test" )
  5. // 创建或者打开一个注册给Lua的C类,"A"表示在Lua中的类名,下次还可打开来加成员
  6. .beginClass<A>( "A" )
  7. // 添加静态属性
  8. .addStaticProperty( "staticData", &A::staticData )
  9. .addStaticProperty( "staticProperty", &A::getStaticProperty, &A::setStaticProperty )
  10. // 添加静态函数
  11. .addStaticFunction( "staticFunc", &A::staticFunc )
  12. .addStaticFunction( "staticCFunc", &A::staticCFunc )
  13. // 添加成员属性
  14. .addProperty( "data", &A::dataMember, false ) // read-only,lua中赋值会报错
  15. .addProperty( "prop", &A::getProperty, &A::setProperty )
  16. // 添加成员函数
  17. .addFunction( "func1", &A::func1 )
  18. .addFunction( "virtualFunc", &A::virtualFunc )
  19. .addFunction( "__tostring", &A::toString ) // 元方法,可注册所有元方法(除__gc),自动为每个类注册析构函数
  20. .addFunction( "cfunc", &A::cfunc )
  21. .endClass()
  22. // 创建一个注册给Lua的类B,它继承自A,注意这是创建,只能调用一次,下次要打开加成员,就用beginClass
  23. // 父类的方法已经在父类注册,这里无需再注册子类的方法
  24. // 如果A没有注册到Lua中,就不需要用derivedClass,用beginClass即可。
  25. .deriveClass<B, A>( "B" )
  26. .addProperty( "data", &B::dataMember2 )
  27. .addFunction( "func1", &B::func1 )
  28. .addFunction( "func2", &B::func2 )
  29. .endClass()
  30. .endNamespace();
  31. // local a = A()
  32. // a.func1() -- error: func1 expects an object of a registered class
  33. // a.func1(a) -- okay, verbose, this how OOP works in Lua
  34. // a:func1() -- okay, less verbose, equvalent to the previous
  35. }
  36. struct A
  37. {
  38. static int staticData;
  39. static float staticProperty;
  40. std::string dataMember;
  41. char dataProperty;
  42. static float getStaticProperty( ) { return staticProperty; }
  43. static void setStaticProperty( float f ) { staticProperty = f; }
  44. static void staticFunc ( ) { }
  45. static int staticCFunc ( lua_State *L ) { return 0; }
  46. char getProperty ( ) const{ return dataProperty; }
  47. void setProperty ( char v ) { dataProperty = v; }
  48. std::string toString ( ) const{ return dataMember; }
  49. void func1 ( ) { }
  50. virtual void virtualFunc ( ) { }
  51. int cfunc ( lua_State *L ) { return 0; }
  52. };
  53. struct B : public A
  54. {
  55. double dataMember2;
  56. void func1 (){}
  57. void func2 (){}
  58. void virtualFunc(){}
  59. };
  60. int A::staticData;
  61. float A::staticProperty;

属性成员代理

对应英文单词property,就是有get/set函数那种。
有时候需要注册的类不是自定义的,而是第三方的,这个类很有可能无法满足注册到Lua的要求,比如没有get/set函数,或者get/set没有正确的函数签名,我们又很可能无法或者不方便修改这个类,这时候可以用一个proxy包装一下。

  1. // 这是个第三方的类,不可修改
  2. struct Vec
  3. {
  4. float coord[3];
  5. };
  6. // 设计一个Proxy类,封装一下Vec
  7. struct VecHelper
  8. {
  9. // get函数,第一个参数必须是被封装的类对象的指针
  10. template <unsigned index>
  11. static float get( Vec const *vec ){ return vec->coord[index]; }
  12. // set函数,第一个参数必须是被封装的类对象的指针
  13. template <unsigned index>
  14. static void set( Vec *vec, float value ){ vec->coord[index] = value; }
  15. };
  16. void fuck( lua_State *L )
  17. {
  18. // 方法一:
  19. luabridge::getGlobalNamespace( L )
  20. .beginNamespace( "test" )
  21. .beginClass<Vec>( "Vec" )
  22. .addProperty( "x", &VecHelper::get<0>, &VecHelper::set<0> )
  23. .addProperty( "y", &VecHelper::get<1>, &VecHelper::set<1> )
  24. .addProperty( "z", &VecHelper::get<2>, &VecHelper::set<2> )
  25. .endClass()
  26. .endNamespace();
  27. // 方法二:通过function
  28. luabridge::getGlobalNamespace( L )
  29. .beginNamespace( "test" )
  30. .beginClass <Vec>( "Vec" )
  31. .addProperty( "x",
  32. std::function <float( const Vec* )>(
  33. []( const Vec* vec ) {return vec->coord[0]; }
  34. ),
  35. std::function <void( Vec*, float )>(
  36. []( Vec* vec, float v ) {vec->coord[0] = v; }
  37. )
  38. )
  39. // ... same for "y" and "z"
  40. .endClass()
  41. .endNamespace();
  42. }

函数成员代理

同上面理,只是换成了addFunction了。

  1. // 这是个第三方的类,不可修改
  2. struct Vec
  3. {
  4. float coord[3];
  5. };
  6. // 直接用
  7. void scale(Vec* vec, float value )
  8. {
  9. vec->coord[0] *= value;
  10. vec->coord[1] *= value;
  11. vec->coord[2] *= value;
  12. };
  13. void fuck( lua_State *L )
  14. {
  15. // 方法一:
  16. luabridge::getGlobalNamespace( L )
  17. .beginNamespace( "test" )
  18. .beginClass<Vec>( "Vec" )
  19. .addFunction( "scale", &scale )
  20. .endClass()
  21. .endNamespace();
  22. // 方法二:通过function
  23. luabridge::getGlobalNamespace( L )
  24. .beginClass<Vec>( "Vec" )
  25. .addFunction( "scaleX",
  26. std::function <void( Vec*, float )>(
  27. []( Vec* vec, float v ) {vec->coord[0] *= v; }
  28. )
  29. )
  30. .endClass();
  31. }

构造函数

可以使用addConstructor为类添加单个构造函数。LuaBridge无法像函数和方法那样自动确定构造函数参数的数量和类型,因此必须提供它们。 这是通过将所需构造函数的签名指定为addConstructor的第一个模板参数来完成的。 将从中提取参数类型(忽略返回类型)。

  1. struct A
  2. {
  3. A();
  4. };
  5. struct B
  6. {
  7. explicit B( char const* s, int nChars );
  8. };
  9. void fuck( lua_State *L )
  10. {
  11. // 方法一:
  12. luabridge::getGlobalNamespace( L )
  13. .beginNamespace( "test" )
  14. // LuaBridge无法自动检测类构造函数的signature,因此我们需要手动传function signature
  15. .beginClass<A>( "A" )
  16. .addConstructor<void( *) ( void )>() // 提供给A构造函数的函数签名
  17. .endClass()
  18. .beginClass<B>( "B" )
  19. .addConstructor<void( *) ( char const*, int )>() // 提供给B的构造函数的函数签名
  20. .endClass()
  21. .endNamespace();
  22. // a = test.A() -- Create a new A.
  23. // b = test.B("hello", 5) -- Create a new B.
  24. // b = test.B() -- Error: expected string in argument 1
  25. }

3、C++调用Lua(LuaRef)

LuaRef类
把LuaRef理解成是C++中和Lua中的变量对等就可以。
LuaRef对象可表示所有Lua数据类型以及注册过来的C类型(类、函数、数据)。
LuaRef对象中存储的值与Lua中的变量遵循相同的规则:表,函数,线程和完整的userdata值是对象。 LuaRef实际上并不包含这些值,仅包含对它们的引用。 赋值,参数传递和函数返回总是操纵对此类值的引用; 这些操作并不意味着任何形式的复制。

  1. LuaRef v( L ); // References nil
  2. LuaRef v1( L, 1 ); // A LUA_TNUMBER
  3. LuaRef v2( L, 1.1 ); // Also a LUA_TNUMBER
  4. LuaRef v3( L, true ); // A LUA_TBOOLEAN
  5. LuaRef v4( L, "string" ); // A LUA_TSTRING
  6. LuaRef v1 = newTable( L ); // Create a new table
  7. LuaRef v2 = getGlobal( L, "print" ); // Reference to _G ["print"]
  8. ......; // A注册给了Lua
  9. LuaRef v( L, new A ); // A LuaBridge userdata holding a pointer to A
  10. v = newTable( L ); // An empty table
  11. v = "string"; // A string. The prevous value becomes eligible for garbage collection.
  12. LuaRef v1( L, "x" ); // assign "x"
  13. LuaRef v2( L, "y" ); // assign "y"
  14. v2 = v1; // v2 becomes "x"
  15. v1 = "z"; // v1 becomes "z", v2 is unchanged
  16. v1 = newTable( L ); // An empty table
  17. v2 = v1; // v2 references the same table as v1
  18. v1 = Nil(); // v1 becomes nil, table is still referenced by v2.

类型转换

  1. void passInt( int );
  2. void passBool( bool );
  3. void passString( std::string );
  4. void passObject( A * );
  5. LuaRef v( L );
  6. //...
  7. passInt( v ); // implicit conversion to int
  8. passBool( v ); // implicit conversion to bool
  9. passString( v ); // implicit conversion to string
  10. passObject( v ); // must hold a registered LuaBridge class or a lua_error() will be called.
  11. // The following are all equivalent:
  12. passString(std::string (v));
  13. passString((std::string)v);
  14. passString(static_cast <std::string> (v));
  15. passString(v.cast<std::string>());

表代理(Table Proxies)
由于表是Lua中唯一的数据结构化机制,因此LuaRef类使用简单,精确的语法为访问和操作表元素提供了强大的功能。 任何可转换类型都可以用作键或值。 将数组索引运算符[]应用于LuaRef会返回一个特殊的临时对象,称为表代理,该对象支持可以在LuaRef上执行的所有操作。 此外,对表代理进行的分配会更改基础表。 由于表代理是编译器创建的临时对象,因此您不能直接使用它们。 LuaBridge表代理不应与Lua中的代理表相混淆。 LuaBridge表代理只是一个中间的C ++类对象,它在幕后工作以使表操作语法符合C ++习惯用法。

  1. LuaRef v = newTable( L );
  2. v["name"] = "John Doe"; // string key, string value
  3. v[1] = 200; // integer key, integer value
  4. v[2] = newTable( L ); // integer key, LuaRef value
  5. v[3] = v[1]; // assign 200 to integer index 3
  6. v[1] = 100; // v[1] is 100, v[3] is still 200
  7. v[3] = v[2]; // v[2] and v[3] reference the same table
  8. v[2] = Nil(); // Removes the value with key = 2. The table is still referenced by v[3].
  9. // t = {}
  10. // t[1] = function() print( "hello" ) end
  11. // t[2] = function( u, v ) print( u, v ) end
  12. // t[3] = "foo"
  13. LuaRef t = getGlobal( L, "t" );
  14. t[1]();
  15. t[2]( "a", "b" );
  16. t[2]( t[1] ); // Call t[3] with the value in t[2]
  17. t[4] = t[3](); // Call t[3] and store the result in t[4].
  18. t[t[5]()] = "wow"; // Store "wow" at the key returned by the call to t[5]
  19. // function fail()
  20. // error( "A problem occurred" )
  21. // end
  22. LuaRef f = getGlobal( L, "fail" );
  23. try {
  24. f();
  25. }
  26. catch( LuaException const &e ) {
  27. std::cerr &&e.what();
  28. }

调用Lua
表代理和LuaRef对象为在适当的引用对象上调用lua_pcall提供了一种方便的语法。 这包括具有适当的__call元方法集的C函数,Lua函数或Lua对象。 提供的实现最多支持八个参数(尽管可以通过添加新功能来支持更多参数)。 任何可转换的C ++类型都可以以其native格式作为参数传递。 函数调用的返回值以LuaRef的形式提供,可以为nil。

  1. // function same( arg1, arg )
  2. // return arg1 == arg2
  3. // end
  4. LuaRef same = getGlobal( L, "same" );
  5. // These all evaluate to true
  6. same( 1, 1 );
  7. !same( 1, 2 );
  8. same( "text", "text" );
  9. !same( 1, "text" );
  10. same( 1, 1, 2 ); // third param ignored

4、LuaStack栈操作

Lua和C通过Lua栈交换数据。LuaBridge利用类模板技术进行了栈操作的封装:

  1. void fuck( lua_State *L )
  2. {
  3. A a("asdfasdfasdf");
  4. Stack<bool> ::push( L, false );
  5. Stack<char> ::push( L, 1 );
  6. Stack<const char *>::push( L, "asdfasdf" );
  7. Stack<std::string> ::push( L, "asdfasdfasdfasdf" );
  8. Stack<int> ::push( L, 1 );
  9. Stack<float> ::push( L, 1 );
  10. Stack<double> ::push( L, 1 );
  11. Stack<A> ::push( L, a ); // 压栈自定义类型,见下面定义
  12. }
  13. class A
  14. {
  15. public:
  16. A( const std::string& str ) { m_strContent = str; }
  17. std::string getContent() { return m_strContent; }
  18. private:
  19. std::string m_strContent;
  20. };
  21. template <>
  22. struct Stack <A>
  23. {
  24. static void push ( lua_State *L, A a ) { lua_pushstring( L, a.getContent().c_str() ); }
  25. static A get ( lua_State *L, int index ) { return A( luaL_checkstring( L, index ) ); }
  26. static bool isInstance( lua_State *L, int index ) { return lua_type( L, index ) == LUA_TSTRING; }
  27. };

5、对象生命周期控制

一个C++对象传递给Lua有以下几种情况:

  • T Passed by value (a copy), with Lua lifetime.
  • T const Passed by value (a copy), with Lua lifetime.
  • T Passed by reference, with *C++ lifetime.
  • T& Passed by reference, with C++ lifetime.
  • T const Passed by const reference, with *C++ lifetime.
  • T const& Passed by const reference, with C++ lifetime.

只有值传递,才由Lua控制对象的生命周期,这很好理解,值传递已经是拷贝了一份给Lua了,C++这边的对象销毁了也没什么影响了。当Lua这边对这个对象进行回收的时候,将触发析构函数,也有可能C++又对这个对象有引用,那C++这边就要注意它的生命周期了。
当Lua是通过注册的构造函数创建的对象,那么这个对象是Lua lifetime。
当是其他情况的时候,将一直由C++控制对象生命周期,Lua使用这个对象时要确保C++这边这个对象还没有被销毁,Lua这边回收这个对象的时候,其实不是回收对象本身,仅仅是对这个对象的引用,并不会触发对象本身的析构。

  1. A a;
  2. B b;
  3. push( L, &a ); // pointer to 'a', C++ lifetime
  4. lua_setglobal( L, "a" );
  5. push( L, ( A const * ) &a ); // pointer to 'a const', C++ lifetime
  6. lua_setglobal( L, "ac" );
  7. push( L, const_cast<A const *>( &a ) ); // equivalent to push (L, (A const*) &a)
  8. lua_setglobal( L, "ac2" );
  9. push( L, new A ); // compiles, but will leak memory
  10. lua_setglobal( L, "ap" );
  11. push (L, b); // Copy of b passed, Lua lifetime.
  12. lua_setglobal (L, "b");
  13. a = nil; collectgarbage () -- 'a' still exists in C++.
  14. b = nil; collectgarbage () -- Lua calls ~B() on the copy of b.

参数传递

  1. // B 继承自 A
  2. void func0( A a );
  3. void func1( A * a );
  4. void func2( A const * a );
  5. void func3( A & a );
  6. void func4( A const & a );
  7. // func0( a ) -- Passes a copy of a, using A's copy constructor.
  8. // func1( a ) -- Passes a pointer to a.
  9. // func2( a ) -- Passes a pointer to a const a. 无法修改a的内容
  10. // func3( a ) -- Passes a reference to a.
  11. // func4( a ) -- Passes a reference to a const a. 无法修改a的内容
  12. // func1( b ) -- 运行正常,B是A的子类,且A、B都注册给Lua了。

共同管理的对象(Shared Lifetime)

就是由C++和Lua共同控制对象的生命周期,只有当任何一方都不在引用对象,对象才会被销毁。
待完成。

四、cocos项目实践

1、C调用Lua

这个用LuaRef完美解决,使用起来非常方便。
https://www.yuque.com/tvvhealth/cs/cs7xf6#KEhG8

2、Lua调用C

  • 如果要调用复杂类体系中的类,比如继承自Node的UI控件等。
    • 选择LuaBinding,因为涉及到庞大的继承体系还有众多类成员,这需要进行大量的注册绑定,用LuaBridge显然不合适,而LuaBinding已经完成这部分工作。
  • 相反,如果调用C中简单类体系中的类,比如没有父类,或者父类比较简单。
    • 选择LuaBridge,注册绑定工作非常简单而且可以动态改变(按需注册成员)
  • 如果就需要注册函数、全局变量
    • 选择LuaBridge,非常简单灵活,LuaBinding过于笨重,且不好维护。

总结起来,如果是要调用cocos内置类及其子类,则用LuaBinding;如果是客户端自定义的类、函数、变量,则推荐LuaBridge:

/// Gets a global Lua variable reference. LuaRef getGlobal( lua_State L, const char name );

/// Sets a global Lua variable. template void setGlobal( lua_State L, V varPtr, const char *name );

/// Gets the global namespace registration object. Namespace getGlobalNamespace( lua_State *L );

  1. <a name="6xU11"></a>
  2. ## 2、Namespace Registration
  3. ```cpp
  4. /// Begins or continues class registration, returns this class object.
  5. template<class T>
  6. Class<T> beginClass( const char *name );
  7. /// Begins derived class registration, returns this class object.
  8. template<class T, class Base>
  9. Class<T> deriveClass( const char *name );
  10. /// Begin or continues namespace registration, returns this namespace object.
  11. template<class T>
  12. Namespace beginNamespace( const char *name );
  13. /// Ends namespace registration, returns the parent namespace object.
  14. template<class T>
  15. Namespace endNamespace();
  16. /// Registers a function.
  17. template<class R, class... Params >>
  18. Namespace addFunction( const char *name,
  19. R( *fn )( Params... ) );
  20. /// Registers a function.
  21. template<class R, class... Params >>
  22. Namespace addFunction( const char *name,
  23. std::function<R( Params... )> fn );
  24. /// Registers a function with an extra Lua state parameter.
  25. template<class R, class... Params >>
  26. Namespace addFunction( const char *name,
  27. R( *fn )( Params..., lua_State * ) );
  28. /// Registers a C-function.
  29. Namespace addFunction( const char *name,
  30. int( *fn )( lua_State * ) );
  31. /// Registers a property with a getter and setter.
  32. template<class V>
  33. Namespace addProperty( const char *name,
  34. V( *getFn )( ),
  35. void( *setFn )( V ) );
  36. /// Registers a property with a getter and setter.
  37. template<class V>
  38. Namespace addProperty( const char *name,
  39. std::function<V()> getFn,
  40. std::function<void( V )> setFn );
  41. /// Registers a property with a C-function getter and setter.
  42. Namespace addProperty( const char *name,
  43. int( *getFn )( lua_State * ),
  44. int( *setFn )( lua_State * ) );
  45. /// Registers a read-only property with a getter function.
  46. template<class V>
  47. Namespace addProperty( const char *name,
  48. V( *getFn )( ) );
  49. /// Registers a read-only property with a getter function.
  50. template<class V>
  51. Namespace addProperty( const char *name,
  52. std::function<V()> getFn );
  53. /// Registers a read-only property with a C-function getter.
  54. Namespace addProperty( const char *name,
  55. int( *getFn )( lua_State * ) );
  56. /// Registers a variable, writable or read-only.
  57. template<class V>
  58. Namespace addVariable( const char *name,
  59. V *varPtr,
  60. bool isWritable = true );

3、Class Registration

  1. /// Open a new or existing class for registrations.
  2. template<class T>
  3. Class<T> beginClass( char const *name );
  4. /// Derive a new class for registrations.
  5. /// Call deriveClass() only once.
  6. /// To continue registrations for the class later, use beginClass().
  7. template<class Derived, class Base>
  8. Class<Derived> deriveClass( char const *name );
  9. /// Ends class registration, returns the parent namespace object.
  10. template<class T>
  11. Namespace endClass();

Member Function Registration

  1. /// Registers a member function.
  2. template<class R, class... Params >>
  3. Namespace addFunction( const char *name, R( T::* fn )( Params... ) );
  4. /// Registers a function.
  5. template<class R, class... Params >>
  6. Namespace addFunction( const char *name, std::function<R( Params... )> fn );
  7. /// Registers a function with an extra Lua state parameter.
  8. template<class R, class... Params >>
  9. Namespace addFunction( const char *name, R( T::* fn )( Params..., lua_State * ) );
  10. /// Registers a C-function.
  11. Namespace addFunction( const char *name, int( *fn )( lua_State * ) );

Member Property Registration

  1. /// Registers a property with a getter and setter.
  2. template<class V>
  3. Namespace addProperty( const char *name,
  4. V( T::* getFn )( ),
  5. void ( T::* setFn )( V ) );
  6. /// Registers a property with a getter and setter.
  7. template<class V>
  8. Namespace addProperty( const char *name,
  9. std::function<V()> getFn,
  10. std::function<void( V )> setFn );
  11. /// Registers a property with a C-function getter and setter.
  12. Namespace addProperty( const char *name,
  13. int( *getFn )( lua_State * ),
  14. int( *setFn )( lua_State * ) );
  15. /// Registers a read-only property with a getter member function.
  16. template<class V>
  17. Namespace addProperty( const char *name, V( T::* getFn )( ) );
  18. /// Registers a read-only property with a getter function.
  19. template<class V>
  20. Namespace addProperty( const char *name, std::function<V()> getFn );
  21. /// Registers a read-only property with a C-function getter.
  22. Namespace addProperty( const char *name, int( *getFn )( lua_State * ) );
  23. /// Registers a member variable, writable or read-only.
  24. template<class V>
  25. Namespace addData( const char *name, V T::* varPtr, bool isWritable = true );

Static Function Registration

  1. /// Registers a function.
  2. template<class R, class... Params >>
  3. Namespace addStaticFunction( const char *name, R( *fn )( Params... ) );
  4. /// Registers a function.
  5. template<class R, class... Params >>
  6. Namespace addStaticFunction( const char *name, std::function<R( Params... )> fn );
  7. /// Registers a function with an extra Lua state parameter.
  8. template<class R, class... Params >>
  9. Namespace addStaticFunction( const char *name, R( *fn )( Params..., lua_State * ) )
  10. /// Registers a C-function.
  11. Namespace addStaticFunction( const char *name, int( *fn )( lua_State * ) );

Static Property Registration

  1. /// Registers a property with a getter and setter.
  2. template<class V>
  3. Namespace addStaticProperty( const char *name, V( *getFn )( ), void( *setFn )( V ) );
  4. /// Registers a property with a getter and setter.
  5. template<class V>
  6. Namespace addStaticProperty( const char *name,
  7. std::function<V()> getFn,
  8. std::function<void( V )> setFn );
  9. /// Registers a property with a C-function getter and setter.
  10. Namespace addStaticProperty( const char *name,
  11. int( *getFn )( lua_State * ),
  12. int( *setFn )( lua_State * ) );
  13. /// Registers a read-only property with a getter function.
  14. template<class V>
  15. Namespace addStaticProperty( const char *name, V( *getFn )( ) );
  16. /// Registers a read-only property with a getter function.
  17. template<class V>
  18. Namespace addStaticProperty( const char *name, std::function<V()> getFn );
  19. /// Registers a read-only property with a C-function getter.
  20. Namespace addStaticProperty( const char *name, int( *getFn )( lua_State * ) );
  21. /// Registers a variable, writable or read-only.
  22. Namespace addStaticData( const char *name, T *varPtr, bool isWritable = true );

4、Lua Variable Reference - LuaRef

  1. /// Creates a nil reference.
  2. LuaRef( lua_State* L );
  3. /// Returns native Lua string representation.
  4. std::string tostring() const;
  5. /// Dumps reference to a stream.
  6. void print( std::ostream& stream ) const;
  7. /// Returns the Lua state.
  8. lua_State* state() const;
  9. /// Place the object onto the Lua stack.
  10. void push( lua_State* L );
  11. /// Return the lua_type.
  12. int type() const;
  13. /// Perform the explicit type conversion.
  14. template<class T>
  15. T cast() const;
  16. /// Check if the Lua value is convertible to the type T.
  17. template<class T>
  18. bool isInstance() const;

5、Stack Traits - Stack

  1. /// Converts the C++ value into the Lua value at the top of the Lua stack.
  2. void put( lua_State* L, T value );
  3. /// Converts the Lua value at the index into the C++ value of the type T.
  4. T get( lua_State* L, int index );
  5. /// Checks if the Lua value at the index is convertible into the C++ value of the type T.
  6. bool isInstance( lua_State* L, int index );