Lua/C++ :即使表的字段已知,也始终调用__index
Lua/C++ : __index is always invoked even the table's field is known
我想在Lua中声明由C++应用程序注册的全局元表。
我定义了元表和一些字段的__index元方法,但当lua脚本访问已知字段时,__index总是在我的C++应用程序中调用。
例如,我想注册一个名为User的全局表,该表包含三个字段:FirstName、LastNamege。
这是我登记桌子的方法。该表被封装在一个名为TLuaStruct的类中,这样可以更容易地在Lua中注册表。
bool TLuaStruct::InternalRegister( std::string tName, bool AddInGC )
{
TLuaStack *ptStack;
TLuaStruct **ptUserLuaStruct;
ptStack = m_ptLua->GetStack();
if( ptStack==NULL )
return false;
// Create a metatable that won't be exposed to Lua scripts.
// The name must be unique
// Stack after the call:
// 1,-1 | table
m_ptLua->NewMetaTable( m_tMetaName );
// Register all of the properties
PushProperties( false, false );
// Register the callback assigned to __index
ptStack->PushCFunction( TLuaStruct_Index_CallBack );
m_ptLua->SetField( -2, "__index" );
// Create a UserData to store the address of this.
// Stack after the call:
// 2,-1 | userdata
// 1,-2 | table
ptUserLuaStruct = ( TLuaStruct** )m_ptLua->NewUserData( sizeof( ptUserLuaStruct ) );
*ptUserLuaStruct = this;
m_pvLuaThisPtr = ( void* )ptUserLuaStruct;
// Switch the userdata and the table
// Stack after the call:
// 2,-1 | table
// 1,-2 | userdata
ptStack->Insert( -2 );
// Associate the metatable to the userdata
// Stack after the call:
// 1,-1 | userdata
m_ptLua->SetMetaTable( -2 );
m_ptLua->SetGlobal( tName.c_str() );
return true;
}
如果我将元表本身分配给__index,而不是C回调,脚本可以只读访问FirstName、LastNamege(我想做什么),但我不知道脚本何时尝试访问未知字段,因为我的C++应用程序没有被调用。
当元表是userdata时,Lua可能总是调用__index,这样它可以确保值是最新的,但最好在表中定义只读变量,比如函数,否则一直调用__index会减慢应用程序的速度。
有人知道怎么表演吗?谢谢
手册很好地解释了元表是如何工作的,也许你误解了它——元表中的任意字段没有效果,只有__index
向对象添加了"假"字段。
最好的解决方案是将所有静态值放在__index
表中,然后为__index
表创建另一个元表,并将其__index
字段设置为函数。
更新:正如其他人所提到的,存在一个稍微紧凑的解决方案:将第一个元表的__index
设置为它自己(并用静态值填充它),并将的元表设置为另一个元表,它将您的函数作为它的__index
。
解决方案:
Riv的解决方案几乎是对的,但有一点不同,所以我发布了一个新的答案。
解决方案是将主元表的__index设置为自己,创建第二个元表,其中它的__index被设置为C回调函数,并将这个新的元表设置为主元表的元表,而不是其__index。
bool TLuaStruct::InternalRegister( std::string tName, bool AddInGC )
{
TLuaStack *ptStack;
TLuaStruct **ptUserLuaStruct;
ptStack = m_ptLua->GetStack();
if( ptStack==NULL )
return false;
// Create a metatable that won't be exposed to Lua scripts.
// The name must be unique
// Stack after the call:
// 1,-1 | table
m_ptLua->NewMetaTable( m_tMetaName );
// Register all of the const members
PushProperties( false, false );
// Duplicate the metatable
// Stack after the call:
// 2,-1 | table
// 1,-2 | table
ptStack->PushValue( -1 );
// Set its __index to itself so it can access all of its const members
// Stack after the call:
// 1,-1 | table
m_ptLua->SetField( -2, "__index" );
// Create another metable that will be used for non-const members
// Stack after the call:
// 2,-1 | table
// 1,-2 | table
m_ptLua->NewMetaTable( "9999" );
// Push the C call back called when a non-const member is read
// Stack after the call:
// 3,-1 | function
// 2,-2 | table
// 1,-3 | table
ptStack->PushCFunction( TLuaStruct_Index_CallBack );
// Set the __index of the metable
// Stack after the call:
// 2,-1 | table
// 1,-2 | table
m_ptLua->SetField( -2, "__index" );
// Set the metatable of the main metatable
// Stack after the call:
// 1,-1 | table
m_ptLua->SetMetaTable( -2 );
// Create a UserData to store the address of this.
// Stack after the call:
// 2,-1 | userdata
// 1,-2 | table
#warning check whether we must create a new pointer each time...
ptUserLuaStruct = ( TLuaStruct** )m_ptLua->NewUserData( sizeof( ptUserLuaStruct ) );
*ptUserLuaStruct = this;
m_pvLuaThisPtr = ( void* )ptUserLuaStruct;
// Switch the userdata and the table
// Stack after the call:
// 2,-1 | table
// 1,-2 | userdata
ptStack->Insert( -2 );
// Set the metatable of the userdata
// Stack after the call:
// 1,-1 | userdata
m_ptLua->SetMetaTable( -2 );
// Publish the userdata object with the name of the module.
// Stack after the call:
// -- empty --
m_ptLua->SetGlobal( tName.c_str() );
return true;
}
- 在提升multi_index容器中,是否定义了"default index"?
- 什么时候调用组成单元对象的析构函数
- 对RValue对象调用的LValue ref限定成员函数
- 为什么使用 "this" 指针调用派生成员函数?
- 函数调用中参数的顺序重要吗
- OpenGL - 在抛出"__gnu_cxx::recursive_init_error"实例后终止调用?
- 基于另一个成员参数将函数调用从类传递给它的一个成员
- 为什么我的C#代码在调用回C++COM直到Task时会暂停.等待/线程.加入
- 在c++类上调用void函数
- 为什么 std::unique 不调用 std::sort?
- 调用专用模板时出错"no matching function for call to [...]"
- 选择要调用的构造函数
- C++为什么尽管我调用了void函数,它却不起作用
- 构造函数正在调用一个使用当前类类型的函数
- 变量没有改变?通过向量的函数调用
- 没有为自己的结构调用列表推回方法
- 调用'begin(int [n])'没有匹配函数
- 什么时候调用析构函数
- 如何用参数值调用函数(仅在运行时已知)
- std::cout.imbue()多重调用