title: Storing reference to lua function in C
body: <p>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.</p>
  
  <p>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 <code>lua_getglobal</code> and <code>lua_pcall</code>), but I would prefer to store a reference to the function itself, so that I can pass a Lua function directly to <code>registerListener</code></p>
  
  <p><strong>Note</strong> It is acceptable to assume that userdata will be <code>NULL</code> for all Lua Listeners.</p>
  
  <p>Here's my code:</p>
  
  <p>EventManager.h</p>
  
  <pre><code>#include &lt;string&gt;
  #include &lt;map&gt;
  #include &lt;vector&gt;
  
  using namespace std;
  
  typedef void (*fptr)(const void* userdata, va_list args);
  typedef pair&lt;fptr, void*&gt; Listener;
  typedef map&lt;string, vector&lt;Listener&gt; &gt; CallbackMap;
  
  class EventManager {
  private:
      friend ostream&amp; operator&lt;&lt;(ostream&amp; out, const EventManager&amp; r);
  
      CallbackMap callbacks;
      static EventManager* emInstance;
      EventManager() {
          callbacks = CallbackMap();
      }
      ~EventManager() {
      }
  public:
      static EventManager* Instance();
      bool RegisterEvent(string const&amp; name);
      void RegisterListener(string const &amp;event_name, fptr callback,
              void* userdata);
      bool FireEvent(string name, ...);
  };
  
  inline ostream&amp; operator&lt;&lt;(ostream&amp; out, const EventManager&amp; em) {
      return out &lt;&lt; "EventManager: " &lt;&lt; em.callbacks.size() &lt;&lt; " registered event"
              &lt;&lt; (em.callbacks.size() == 1 ? "" : "s");
  }
  </code></pre>
  
  <p>EventManager.cpp</p>
  
  <pre><code>#include &lt;cstdarg&gt;
  #include &lt;iostream&gt;
  #include &lt;string&gt;
  
  #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&amp; name) {
      if (!callbacks.count(name)) {
          callbacks[name] = vector&lt;Listener&gt;();
          return true;
      }
  
      return false;
  }
  
  void EventManager::RegisterListener(string const &amp;event_name, fptr callback,
          void* userdata) {
      RegisterEvent(event_name);
      callbacks[event_name].push_back(Listener(callback, userdata));
  }
  
  bool EventManager::FireEvent(string name, ...) {
      map&lt;string, vector&lt;Listener&gt; &gt;::iterator event_callbacks =
              callbacks.find(name);
      if (event_callbacks == callbacks.end()) {
          return false;
      }
  
      for (vector&lt;Listener&gt;::iterator cb =
              event_callbacks-&gt;second.begin();
              cb != event_callbacks-&gt;second.end(); ++cb) {
          va_list args;
          va_start(args, NULL);
          (*cb-&gt;first)(cb-&gt;second, args);
          va_end(args);
      }
  
      return true;
  }
  </code></pre>
  
  <p>luaw_eventmanager.h</p>
  
  <pre><code>#pragma once
  #ifndef LUAW_EVENT_H
  #define LUAW_EVENT_H
  
  #include "EventManager.h"
  
  extern "C" {
  
  #include &lt;lua.h&gt;
  #include &lt;lauxlib.h&gt;
  #include &lt;lualib.h&gt;
  
  void luaw_eventmanager_push(lua_State* L, EventManager* em);
  int luaopen_weventmanager(lua_State* L);
  
  }
  #endif
  </code></pre>
  
  <p>luaw_eventmanager.cpp</p>
  
  <pre><code>#include &lt;assert.h&gt;
  #include &lt;stdio.h&gt;
  
  #include &lt;sstream&gt;
  #include &lt;iostream&gt;
  
  #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 &lt;&lt; luaL_checkstring(L, 2);
  
      EventManager::Instance()-&gt;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 &lt;&lt; *EventManager::Instance();
      lua_pushstring(L, &amp;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;
  }
  </code></pre>