在C中存储对lua函数的引用 [英] Storing reference to lua function in C
问题描述
我有一个用C ++实现的基本事件处理程序.我的应用程序中也有一个嵌入式Lua解释器,需要与事件管理器进行交互.最终目标是能够拥有一个事件处理程序,该事件处理程序在触发事件时将同时执行c ++和Lua函数.
I have a basic event handler implemented in C++. I also have an embedded Lua interpreter in my application that I need to interact with the Event Manager. The ultimate goal is to be able to have one event handler that will execute both c++ and Lua functions when an event is fired.
我的问题是我无法想出一种简单的方法来在我的C ++代码中存储对lua函数的引用.我知道如何从c(使用lua_getglobal
和lua_pcall
)执行Lua函数,但是我更喜欢存储对该函数本身的引用,以便可以将Lua函数直接传递给registerListener
My problem is that I can't come up with a simple way to store references to the lua functions in my C++ code. I know how to execute Lua functions from c (using lua_getglobal
and lua_pcall
), but I would prefer to store a reference to the function itself, so that I can pass a Lua function directly to registerListener
注意可以接受的是,假设所有Lua侦听器的用户数据都为NULL
.
Note It is acceptable to assume that userdata will be NULL
for all Lua Listeners.
这是我的代码:
EventManager.h
EventManager.h
#include <string>
#include <map>
#include <vector>
using namespace std;
typedef void (*fptr)(const void* userdata, va_list args);
typedef pair<fptr, void*> Listener;
typedef map<string, vector<Listener> > CallbackMap;
class EventManager {
private:
friend ostream& operator<<(ostream& out, const EventManager& r);
CallbackMap callbacks;
static EventManager* emInstance;
EventManager() {
callbacks = CallbackMap();
}
~EventManager() {
}
public:
static EventManager* Instance();
bool RegisterEvent(string const& name);
void RegisterListener(string const &event_name, fptr callback,
void* userdata);
bool FireEvent(string name, ...);
};
inline ostream& operator<<(ostream& out, const EventManager& em) {
return out << "EventManager: " << em.callbacks.size() << " registered event"
<< (em.callbacks.size() == 1 ? "" : "s");
}
EventManager.cpp
EventManager.cpp
#include <cstdarg>
#include <iostream>
#include <string>
#include "EventManager.h"
using namespace std;
EventManager* EventManager::emInstance = NULL;
EventManager* EventManager::Instance() {
if (!emInstance) {
emInstance = new EventManager;
}
return emInstance;
}
bool EventManager::RegisterEvent(string const& name) {
if (!callbacks.count(name)) {
callbacks[name] = vector<Listener>();
return true;
}
return false;
}
void EventManager::RegisterListener(string const &event_name, fptr callback,
void* userdata) {
RegisterEvent(event_name);
callbacks[event_name].push_back(Listener(callback, userdata));
}
bool EventManager::FireEvent(string name, ...) {
map<string, vector<Listener> >::iterator event_callbacks =
callbacks.find(name);
if (event_callbacks == callbacks.end()) {
return false;
}
for (vector<Listener>::iterator cb =
event_callbacks->second.begin();
cb != event_callbacks->second.end(); ++cb) {
va_list args;
va_start(args, NULL);
(*cb->first)(cb->second, args);
va_end(args);
}
return true;
}
luaw_eventmanager.h
luaw_eventmanager.h
#pragma once
#ifndef LUAW_EVENT_H
#define LUAW_EVENT_H
#include "EventManager.h"
extern "C" {
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
void luaw_eventmanager_push(lua_State* L, EventManager* em);
int luaopen_weventmanager(lua_State* L);
}
#endif
luaw_eventmanager.cpp
luaw_eventmanager.cpp
#include <assert.h>
#include <stdio.h>
#include <sstream>
#include <iostream>
#include "luaw_eventmanager.h"
using namespace std;
static int
luaw_eventmanager_registerevent(lua_State* L)
{
int nargs = lua_gettop(L);
if (nargs != 2) {
return 0;
}
stringstream ss;
ss << luaL_checkstring(L, 2);
EventManager::Instance()->RegisterEvent(ss.str());
return 1;
}
static int
luaw_eventmanager_registerlistener(lua_State* L)
{
return 1;
}
static int
luaw_eventmanager_fireevent(lua_State* L)
{
return 1;
}
static int
luaw_eventmanager_tostring(lua_State* L)
{
stringstream ss;
ss << *EventManager::Instance();
lua_pushstring(L, &ss.str()[0]);
return 1;
}
static const struct luaL_Reg luaw_eventmanager_m [] = {
{"registerEvent", luaw_eventmanager_registerevent},
{"registerListener", luaw_eventmanager_registerlistener},
{"fireEvent", luaw_eventmanager_fireevent},
{"__tostring", luaw_eventmanager_tostring},
{NULL, NULL}
};
void
luaw_eventmanager_push(lua_State* L, EventManager* em)
{
EventManager** emUserdata = (EventManager**)lua_newuserdata(L, sizeof(EventManager*));
*emUserdata = em;
luaL_getmetatable(L, "WEAVE.mEventManager");
lua_setmetatable(L, -2);
}
int
luaopen_weventmanager(lua_State* L)
{
luaL_newmetatable(L, "WEAVE.mEventManager");
lua_pushvalue(L, -1);
lua_setfield(L, -2, "__index");
luaL_register(L, NULL, luaw_eventmanager_m);
assert(!lua_isnil(L, -1));
return 1;
}
推荐答案
我建议将您的函数存储在注册表中,并使用函数luaL_ref
和luaL_unref
提供的引用机制
I would suggest to store your functions into the registry and use the reference mechanism provided by the functions luaL_ref
and luaL_unref
.
这些函数使用C int
值访问这些值.例如,将这样的整数值存储在C ++类成员中很容易.
These functions use an C int
value to access the values. It is easy to store such an integer value in a C++ class member for example.
这篇关于在C中存储对lua函数的引用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!