- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
编辑:[答案 2 中的解决方案]
我是 LUA 的新手,在尝试做我想做的事情时遇到了麻烦。我有一个看起来像这样的 C++ 对象:
C++ 对象定义
struct TLimit
{
bool enabled;
double value;
TLimit() : enabled(false), value(0.0) {}
~TLimit() {}
};
class TMeaurement
{
public:
TMeasurement() : meas(0.0) {}
~TMeasurement() {}
TLimit min;
TLimit max;
double meas;
};
我希望能够在 LUA 中访问以下形式的 TMeasurement 类型的对象:
LUA 所需用途
-- objmeas is an instance of TMeasurement
objmeas.min.enabled = true
print(objmeas.min.value);
...等等
另一件事,我不希望 LUA 为 TMeasurement 类型的对象实例分配内存。这将在我的 C++ 代码中完成。我尝试了很多不同的事情,但都没有成功。我现在将发布我的最后一次尝试。
在我的 C++ 代码中,我定义了以下内容:
TLimit - 获取将映射到 __index 的函数
#define LUA_MEAS_LIMIT "itse.measurement.limit"
extern int llim_get(lua_State* L)
{
TLimit* lim = (TLimit*)lua_chekuserdata(L, 1, LUA_MEAS_LIMIT);
std::string key = std::string(luaL_checkstring(L, 2));
//-- this is only to check what is going on
std::cout << "lim.get: " << key << std::endl;
if(key.find("enabled") == 0)
lua_pushboolean(L, lim->enabled);
else if(key.find("value") == 0)
lua_pushnumber(L, lim->value);
else
return 0; //-- should return some sort of error, but let me get this working first
return 1;
}
TLimit - 设置将映射到 __newindex 的函数
extern int llim_set(lua_State* L)
{
TLimit* lim = (TLimit*)lua_chekuserdata(L, 1, LUA_MEAS_LIMIT);
std::string key = std::string(luaL_checkstring(L, 2));
//-- this is only to check what is going on
std::cout << "limit.set: " << key << " <-" << std::endl;
if(key.find("enabled") == 0)
lim->enabled = lua_toboolean(L, 3);
else if(key.find("value") == 0)
lim->value = lua_tonumber(L, 3);
return 0;
}
现在,TMeasurement 类还有一个函数。 (我不会在这个例子中提供成员“meas”的设置函数)。
TMeasurement - 获取 __index 的函数
#define LUA_MEASUREMENT "itse.measurement"
extern int lmeas_get(lua_State* L)
{
TMeasurement* test = (TMeasurement*)lua_checkuserdata(L, 1, LUA_MEASUREMENT);
std::string key = std::string(luaL_checkstring(L, 2));
//-- this is only to check what is going on
std::cout << "meas." << key << " ->" << std::endl;
if(key.find("meas") == 0)
lua_pushinteger(L, test->meas);
else if(key.find("min") == 0)
{
lua_pushlightuserdata(L, &test->min);
luaL_getmetatable(L, LUA_MEAS_LIMIT);
lua_setmetatable(L, -2);
}
else if(key.find("max") == 0)
{
lua_pushlightuserdata(L, &test->max);
luaL_getmetatable(L, LUA_MEAS_LIMIT);
lua_setmetatable(L, -2);
}
else
return 0; //-- should notify of some error... when I make it work
return 1;
}
现在,代码中为这两个对象创建 mettatable 的部分:
C++ - 发布元表
(没关系 nsLUA::safeFunction<...> 位,它只是一个模板函数,将在“安全模式”下执行 < > 中的函数...它会弹出一个 MessaegBox 时遇到错误)
static const luaL_Reg lmeas_limit_f[] = { { NULL, NULL} };
static const luaL_Reg lmeas_limit[] =
{
{ "__index", nsLUA::safeFunction<llim_get> },
{ "__newindex", nsLUA::safeFunction<lllim_set> },
{ NULL, NULL }
};
//-----------------------------------------------------------------------------
static const luaL_Reg lmeas_f[] = { { NULL, NULL} };
static const luaL_Reg lmeas[] =
{
{ "__index", nsLUA::safeFunction<lmeas_get> },
{ NULL, NULL }
};
//-----------------------------------------------------------------------------
int luaopen_meas(lua_State* L)
{
//-- Create Measurement Limit Table
luaL_newmetatable(L, LUA_MEAS_LIMIT);
luaL_setfuncs(L, lmeas_limit, 0);
luaL_newlib(L, lmeas_limit_f);
//-- Create Measurement Table
luaL_newmetatable(L, LUA_MEASUREMENT);
luaL_setfuncs(L, lmeas, 0);
luaL_newlib(L, lmeas_f);
return 1;
}
最后,我在 C++ 中的主要函数初始化 LUA,创建对象 TMeasurement 的实例,将其作为全局传递给 LUA 并执行 lua 脚本。大多数此功能包含在另一个名为 LEngine 的类中:
C++ - 主要函数
int main(int argc, char* argv[])
{
if(argc < 2)
return show_help();
nsLUA::LEngine eng;
eng.runScript(std::string(argv[1]));
return 0;
}
//-----------------------------------------------------------------------------
int LEngine::runScript(std::string scrName)
{
//-- This initialices LUA engine, openlibs, etc if not already done. It also
// registers whatever library I tell it so by calling appropriate "luaL_requiref"
luaInit();
if(m_lua) //-- m_lua is the lua_State*, member of LEngine, and initialized in luaInit()
{
LMeasurement measurement;
measurement.value = 4.5; //-- for testing purposes
lua_pushlightuserdata(m_lua, &tst);
luaL_getmetatable(m_lua, LUA_MEASUREMENT);
lua_setmetatable(m_lua, -2);
lua_setglobal(m_lua, "step");
if(luaL_loadfile(m_lua, scrName.c_str()) || lua_pcall(m_lua, 0, 0, 0))
processLuaError(); //-- Pops-up a messagebox with the error
}
return 0;
}
现在,问题终于来了。当我执行任何 lua 脚本时,我可以毫无问题地访问步骤,但我只能第一次访问“min”或“max”内的 memebr ...任何后续访问都会出错。
LUA - 示例一
print(step.meas); -- Ok
print(step.min.enabled); -- Ok
print(step.min.enabled); -- Error: attempt to index field 'min' (a nil value)
此脚本生成的输出是:
first script line: print(step.meas);
meas.meas -> this comes from lmeas_get function
4.5 this is the actual print from lua sentence
second script line: print(step.min.enabled)
meas.min -> accessing step.min, call to function lmeas_get
limit.get: enabled -> accessing min.enabled, call to function llim_get
false actual print from script sentence
third script line: print(step.min.enabled)
limit.get: min -> accessing min from limit object, call to llim_get ???????
所以。在我第一次访问字段“min”(或“max”)之后,任何后续访问它的尝试都将返回“尝试访问索引...”错误。我是先访问 __index (local e = step.min.enabled) 函数还是访问 __newindex 函数 (step.min.enabled = true) 并不重要。
似乎我在第一次访问对象步骤的最小元表时弄乱了 LUA 堆栈。它以某种方式将“指向步骤的指针”从 LUA_MEASUREMENT 元表“替换”为 LUA_MEAS_LIMIT...我只是不知道为什么。
请帮忙...我怎么搞砸了这么多?
谢谢你,抱歉发了这么长的帖子……我只是不知道如何让它更短。
最佳答案
首先,感谢@siffiejoe 和@greatwolf 的帖子。是他们向我解释了我做错了什么。
现在,我的解决方案。我很确定这个解决方案并不是最好的,但它满足了我目前的需求。如果有人有任何建议,查看/发现潜在的错误,或者只是想发表评论,请这样做。
解决方案 - 想法
由于在 LUA 中,所有 lightuserdata 共享相同的元表,我决定让所有我想将 lightuserdata 指针传递给 LUA 的结构和类共享相同的继承 self 称为 LMetaPointer
。此类将发布元表并将 __index
和 __newindex
映射到给定的静态方法 LMetaPointer::__index
和 LMetaPointer::__newindex
。该类还包含一个 static std::map
(列表)指针,指向曾经创建的所有 LMetaPointer
实例。该类的构造函数确保将新创建的实例添加到该映射中。
每当在 lua 中,元方法 __index
或 __newindex
被调用时,相应的 LMetaPointer::__index
或 LMetaPointer::__newindex
被执行。该方法在map中查找对应的负责方法调用的指针,并调用自己的get
或set
方法,这些方法在中定义为纯虚函数LMetaPointer
类。
我知道这可能有点令人困惑,所以我现在将发布类 LMetaPointer
的定义
解决方案——框架:LMetaPointer类
//-----------------------------------------------------------------------------
#define LUA_METAPOINTER "itse.metapointer" //-- Name given to the metatable for all lightuserdata (instances of LMetaPointer in C++)
//-----------------------------------------------------------------------------
class LMetaPointer
{
private:
static lua_State* m_lua; //-- All LMetaPointers will share a common lua State
static const luaL_Reg m_lmembers[]; //-- Member functions (for later expansion)
static const luaL_Reg m_lfunctions[]; //-- Metamethods
static std::map<LMetaPointer*, std::string> m_pointers; //-- List of all LMetaPointer instances
std::string m_name; //-- Name of LUA global variable pointing to me.
static int __index(lua_State* L); //-- Shall be mapped to __index metamethod of the metatable for all lightuserdata pointers
static int __newindex(lua_State* L); //-- Shall be mapped to __newindex metamethod of the metatable for all lightuserdata pointers
void initialize(lua_State* L); //-- Creates the metatable (only once) and publishes it
protected:
public:
LMetaPointer(lua_State* L);
virtual ~LMetaPointer();
inline lua_State* lua() { return m_lua; }
inline std::string global() { return m_name; }
inline size_t size() { return m_pointers.size(); }
void setGlobal(std::string n); //-- Shall make this pointer globally accessible to LUA
virtual int get(lua_State* L) = 0; //-- To be implemented by inherited classes
virtual int set(lua_State* L) = 0; //-- To be implemented by inherited classes
LMetaPointer* operator [](std::string n);
};
下面是类的实现
//-----------------------------------------------------------------------------
#define lua_checkmpointer(L) (LMetaPointer*)luaL_checkudata(L, 1, LUA_METAPOINTER)
//-----------------------------------------------------------------------------
lua_State* LMetaPointer::m_lua = NULL;
std::map<LMetaPointer*, std::string> LMetaPointer::m_pointers;
const luaL_Reg LMetaPointer::m_lmembers[] = { { NULL, NULL } };
const luaL_Reg LMetaPointer::m_lfunctions[] =
{
{ "__index", LMetaPointer::__index },
{ "__newindex", LMetaPointer::__newindex },
{ NULL, NULL }
};
//-----------------------------------------------------------------------------
LMetaPointer::LMetaPointer(lua_State* L) : m_name("")
{
//-- Make sure we have created the metatable
initialize(L);
//-- Add this pointer as of kind LUA_METAPOINTER metatable. This bit of code
// might not be necessary here. (To be removed)
lua_pushlightuserdata(m_lua, this);
luaL_getmetatable(m_lua, LUA_METAPOINTER);
lua_setmetatable(m_lua, -2);
//-- Add myself to the map of all metapointers
m_pointers[this] = m_name;
}
//-----------------------------------------------------------------------------
LMetaPointer::~LMetaPointer()
{
//-- Remove myself from the map of metapointers
std::map<LMetaPointer*, std::string>::iterator found = m_pointers.find(this);
if(found != m_pointers.end())
m_pointers.erase(found);
}
//-----------------------------------------------------------------------------
int LMetaPointer::__index(lua_State* L)
{
//-- Obtain the object that called us and call its get method.
// Since get and set are pure virtual, all inherited classes of LMetaPointer
// must implement it, and, upon the call from here, the correct 'get' method
// will be called.
LMetaPointer* p = lua_checkmpointer(L);
return p->get(L);
}
//-----------------------------------------------------------------------------
int LMetaPointer::__newindex(lua_State* L)
{
//-- Obtain the object that called us and call its set method
// Since get and set are pure virtual, all inherited classes of LMetaPointer
// must implement it, and, upon the call from here, the correct 'get' method
// will be called.
LMetaPointer* p = lua_checkmpointer(L);
return p->set(L);
}
//-----------------------------------------------------------------------------
void LMetaPointer::initialize(lua_State* L)
{
//-- Only create the metatable the first time and instance of LMetaPointer is created
if(!m_lua)
{
m_lua = L;
luaL_newmetatable(m_lua, LUA_METAPOINTER);
luaL_setfuncs(L, m_lfunctions, 0);
luaL_newlib(L, m_lmembers);
}
}
//-----------------------------------------------------------------------------
void LMetaPointer::setGlobal(std::string n)
{
//-- Make myself (this) a global variable in LUA with name given by 'n'
std::map<LMetaPointer*, std::string>::iterator found = m_pointers.find(this);
if(found != m_pointers.end())
{
m_name = n;
found->second = m_name;
lua_pushlightuserdata(m_lua, this);
luaL_getmetatable(m_lua, LUA_METAPOINTER);
lua_setmetatable(m_lua, -2);
lua_setglobal(m_lua, m_name.c_str());
}
}
//-----------------------------------------------------------------------------
LMetaPointer* LMetaPointer::operator [](std::string n)
{
//-- Simply for completeness, allow all metapointer access all other by their
// name. (Notice though that since names are only assigned to instances made
// global, this operator will only work properly when searching for a pointer
// made global. ALl othe rpointers have an empty name.
std::map<LMetaPointer*, std::string>::iterator iter = m_pointers.begin();
while(iter != m_pointers.end())
{
if(iter->second == n)
return iter->first;
++iter;
}
return NULL;
}
现在,这个类将允许我定义任何其他结构或类,并向 LUA 传递一个指向它的指针 (lightuserdata),而无需混合方法或名称。对于我最初问题中的示例,这意味着定义以下内容:
注意:我对示例进行了一些扩展,现在称为 LMeasLimit
的是以前的 TLimit
,LMeasurement
是新的类和 LTest
是前面的 TMeaasurement
解决方案 - 实现
//-------------------------------------------------------------------------
struct LMeasLimit : public LMetaPointer
{
bool enabled; //-- Is the limit enabled?
double value; //-- Limit value;
LMeasLimit(lua_State* L) : LMetaPointer(L), enabled(false), value(0.0) {}
~LMeasLimit() {}
int get(lua_State* L); //-- Implements LMetaPointer::get
int set(lua_State* L); //-- Implements LMetaPointer::set
};
//-------------------------------------------------------------------------
struct LMeasurement : public LMetaPointer
{
double value; //-- Measurement
LStepResult result; //-- Result of test
std::string message; //-- Message to display
LMeasurement(lua_State* L) : LMetaPointer(L), value(0.0), result(srNothing), message("") {}
~LMeasurement() {}
int get(lua_State* L); //-- Implements LMetaPointer::get
int set(lua_State* L); //-- Implements LMetaPointer::set
};
//-------------------------------------------------------------------------
struct LTest : public LMetaPointer
{
int id; //-- ID of test
std::string name; //-- Name of test
LMeasLimit max; //-- Max limit for measure
LMeasLimit min; //-- Min limit for measure
LMeasurement meas; //-- Measurement
LTest(lua_State* L) : LMetaPointer(L), id(0), name(""), min(L), max(L), meas(L) {}
~LTest() {}
int get(lua_State* L); //-- Implements LMetaPointer::get
int set(lua_State* L); //-- Implements LMetaPointer::set
};
//-----------------------------------------------------------------------------
以及不同类的不同方法的定义
int LMeasLimit::get(lua_State* L)
{
std::string key = std::string(luaL_checkstring(L, 2));
if(key.find("enabled") == 0)
lua_pushboolean(L, enabled);
else if(key.find("value") == 0)
lua_pushnumber(L, value);
else
return 0;
return 1;
}
//-----------------------------------------------------------------------------
int LMeasLimit::set(lua_State* L)
{
std::string key = std::string(luaL_checkstring(L, 2));
if(key.find("enabled") == 0)
enabled = lua_toboolean(L, 3);
else if(key.find("value") == 0)
value = lua_tonumber(L, 3);
return 0;
}
//-----------------------------------------------------------------------------
int LMeasurement::get(lua_State* L)
{
std::string key = std::string(luaL_checkstring(L, 2));
if(key.find("value") == 0)
lua_pushnumber(L, value);
else if(key.find("result") == 0)
lua_pushunsigned(L, result);
else if(key.find("message") == 0)
lua_pushstring(L, message.c_str());
else
return 0;
return 1;
}
//-----------------------------------------------------------------------------
int LMeasurement::set(lua_State* L)
{
std::string key = std::string(luaL_checkstring(L, 2));
if(key.find("value") == 0)
value = lua_tonumber(L, 3);
else if(key.find("result") == 0)
result = LStepResult(lua_tounsigned(L, 3));
else if(key.find("message") == 0)
message = std::string(lua_tostring(L, 3));
return 0;
}
//-----------------------------------------------------------------------------
int LTest::get(lua_State* L)
{
std::string key = std::string(luaL_checkstring(L, 2));
if(key.find("id") == 0)
lua_pushinteger(L, id);
else if(key.find("name") == 0)
lua_pushstring(L, name.c_str());
else if(key.find("min") == 0)
{
lua_pushlightuserdata(L, &min);
luaL_getmetatable(L, LUA_METAPOINTER);
lua_setmetatable(L, -2);
}
else if(key.find("max") == 0)
{
lua_pushlightuserdata(L, &max);
luaL_getmetatable(L, LUA_METAPOINTER);
lua_setmetatable(L, -2);
}
else if(key.find("meas") == 0)
{
lua_pushlightuserdata(L, &meas);
luaL_getmetatable(L, LUA_METAPOINTER);
lua_setmetatable(L, -2);
}
else
return 0;
return 1;
}
//-----------------------------------------------------------------------------
int LTest::set(lua_State* L)
{
std::string key = std::string(luaL_checkstring(L, 2));
if(key.find("id") == 0)
id = lua_tointeger(L, 3);
else if(key.find("name") == 0)
name = std::string(lua_tostring(L, 3));
return 0;
}
解决方案 - 将所有内容放在一起最后的修改是在我们原始问题的 LEngine::runScript
中。
int LEngine::runScript(std::string scrName)
{
luaInit();
if(m_lua)
{
LTest tst(m_lua);
tst.name = std::string("mierda_esta");
tst.setGlobal("step");
if(luaL_loadfile(m_lua, scrName.c_str()) || lua_pcall(m_lua, 0, 0, 0))
processLuaError();
}
return 0;
}
最后,我将展示我用于测试的 LUA 脚本之一及其输出。
测试 - LUA 脚本
print("step.id = " .. step.id)
print("step.name = " .. step.name)
print(step.min.enabled)
print("step.min.value = " .. step.min.value)
step.id = 1
step.name = "nombre del test";
step.min.enabled = true;
step.min.value = 5.6;
print("step.id = " .. step.id)
print("step.name = " .. step.name)
print(step.min.enabled)
print("step.min.value = " .. step.min.value)
测试 - 输出
step.id = 0
step.name = mierda_esta
false
step.min.value = 0
step.id = 1
step.name = nombre del test
true
step.min.value = 5.6
所以,现在一切似乎都如我所愿。我仍然需要修改此 LMetaPointer
以便能够以与我们在 C++ 中类似的方式调用任何继承类的成员函数。但这将是另一个故事。
再次感谢@siffiejoe 和@greatwolf 的时间和回复。
关于c++ - Lua 5.2 - 对象中的 C++ 对象(使用 lua_lightuserdata),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27378219/
#include using namespace std; class C{ private: int value; public: C(){ value = 0;
这个问题已经有答案了: What is the difference between char a[] = ?string?; and char *p = ?string?;? (8 个回答) 已关闭
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 7 年前。 此帖子已于 8 个月
除了调试之外,是否有任何针对 c、c++ 或 c# 的测试工具,其工作原理类似于将独立函数复制粘贴到某个文本框,然后在其他文本框中输入参数? 最佳答案 也许您会考虑单元测试。我推荐你谷歌测试和谷歌模拟
我想在第二台显示器中移动一个窗口 (HWND)。问题是我尝试了很多方法,例如将分辨率加倍或输入负值,但它永远无法将窗口放在我的第二台显示器上。 关于如何在 C/C++/c# 中执行此操作的任何线索 最
我正在寻找 C/C++/C## 中不同类型 DES 的现有实现。我的运行平台是Windows XP/Vista/7。 我正在尝试编写一个 C# 程序,它将使用 DES 算法进行加密和解密。我需要一些实
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
有没有办法强制将另一个 窗口置于顶部? 不是应用程序的窗口,而是另一个已经在系统上运行的窗口。 (Windows, C/C++/C#) 最佳答案 SetWindowPos(that_window_ha
假设您可以在 C/C++ 或 Csharp 之间做出选择,并且您打算在 Windows 和 Linux 服务器上运行同一服务器的多个实例,那么构建套接字服务器应用程序的最明智选择是什么? 最佳答案 如
你们能告诉我它们之间的区别吗? 顺便问一下,有什么叫C++库或C库的吗? 最佳答案 C++ 标准库 和 C 标准库 是 C++ 和 C 标准定义的库,提供给 C++ 和 C 程序使用。那是那些词的共同
下面的测试代码,我将输出信息放在注释中。我使用的是 gcc 4.8.5 和 Centos 7.2。 #include #include class C { public:
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我的客户将使用名为 annoucement 的结构/类与客户通信。我想我会用 C++ 编写服务器。会有很多不同的类继承annoucement。我的问题是通过网络将这些类发送给客户端 我想也许我应该使用
我在 C# 中有以下函数: public Matrix ConcatDescriptors(IList> descriptors) { int cols = descriptors[0].Co
我有一个项目要编写一个函数来对某些数据执行某些操作。我可以用 C/C++ 编写代码,但我不想与雇主共享该函数的代码。相反,我只想让他有权在他自己的代码中调用该函数。是否可以?我想到了这两种方法 - 在
我使用的是编写糟糕的第 3 方 (C/C++) Api。我从托管代码(C++/CLI)中使用它。有时会出现“访问冲突错误”。这使整个应用程序崩溃。我知道我无法处理这些错误[如果指针访问非法内存位置等,
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 7 年前。
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,因为
我有一些 C 代码,将使用 P/Invoke 从 C# 调用。我正在尝试为这个 C 函数定义一个 C# 等效项。 SomeData* DoSomething(); struct SomeData {
这个问题已经有答案了: Why are these constructs using pre and post-increment undefined behavior? (14 个回答) 已关闭 6
我是一名优秀的程序员,十分优秀!