在C中存储对lua函数的引用 [英] Storing reference to lua function in C

查看:111
本文介绍了在C中存储对lua函数的引用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个用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_getgloballua_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_refluaL_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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆