0
votes

I have a c++ host in which I use tolua++ to expose some classes to Lua. One of the classes has a function that should register a callback from lua. So when the C++ code needs to call a Lua registered function it can. The function is however a table/class function. I've done this before with the string function name (not part of a lua "class") with success but I'm curious if I'm able to somehow store the Lua function and not function name.

I define my lua classes like:

MyClass = {}

function MyClass:Create()
    local obj = {}

    -- copy all functions from MyClass table to this local obj and return it
    local k,v
    for k,v in pairs(obj) do
        obj[k] = v
    end

    return obj
end

function MyClass:Enter()
    self.CPlusClass = CPlusClass:Create()   -- this is the C++ class creation, I defined a static function Create()
    self.CPlusClass:RegisterCallback(15, self.Callback) -- this is where I want to pass this instances function to be called back from the C++ class
end

function MyClass:Callback(reader)
    -- I want to be able to use self here as well so it needs to be the same instance
end

Inside the MyClass:Enter() is where I want to register the lua "class" function MyClass::Callback to be able to be called from the C++ object. How would I pass this into a C++ function? What would the type be so that it will call MyClass:Callback() from C++ also passing in "self" so that it's the same "instance" of the class?

So I know 'self' is referring to an actual variable that I created and I assume will be in the global table by variable name, but when you are inside the lua "class" how can I tell what variable name 'self' is referring too? If I could get that I could pass that to my C++ function and store it as a string so that I can call getglobal on it to get that specific table, and then I could also pass the table function name as string and in C++ I could get that also, and call it. But the question would be, how can I convert 'self' to the actual variable name it's pointing too so I can call getglobal in C++ to get that table?

2
self is not a global, self is an automatic variable defined by the table:function syntactic sugar. function table:class(args...) ... end is identical to function table.class(self, args...) ... end. Similarly a call to tab:class(args...) is identical to tab.class(tab, args...) (though tab is evaluated only once).Etan Reisner
I understand that. self however is referring to a table I created somewhere in my lua program. How can I tell what variable name self is referring to?user441521
You can't disassociate a function from its table "object" and have it work on that table "object" again later. You would need to create a closure as your callback function to do what you wanted to do here.Etan Reisner
self is the variable name. It is the first argument to the function. It is the table on which the function is called.Etan Reisner
but self is referring to a table I created somewhere in the lua program is it not? that table variable name must be in the global table is it not?user441521

2 Answers

2
votes

If you want to keep the RegisterCallback signature and operation (as opposed to enhancing it to understand object method callbacks in some fashion) then you need to create a closure and pass that as the callback. Something like this:

function create_closure(obj, fun)
    return function(...)
        return obj[fun](...)
    end
end

and

function MyClass:Enter()
    self.CPlusClass = CPlusClass:Create()   -- this is the C++ class creation, I defined a static function Create()
    self.CPlusClass:RegisterCallback(15, create_closure(self, "Callback"))
end
3
votes

You exported CPlusClass "class" from C++ to Lua: surely this C++ class has a RegisterCallback which accepts a pointer to a function or to a YourCallbackClass instance which uses virtual methods to dispatch to the correct object. Then all you need is to export YourCallbackClass to Lua: behind the scenes, the Lua version will create an instance and give it to your C++ RegisterCallback. For instance:

class CPlusClass {
public: 
    RegisterCallback(int val, CPlusCallback* cb) { ... store cb for later... }
};

class SomeObj; // type of Objects that you want to call back into

class CPlusCallback {
public:
    typedef void (SomeObj::*Method)();
    CPlusCallback(SomeObj* obj, Method method) { callee=obj; method=method; }
    call() { callee->*Method(); }
private:
    SomeObj* callee; 
    Method method;
};

Your CPlusCallback is likely different, this is just an example. For example if you just want functions not methods then you don't need to store the callee. If you want both, then CPlusCallback must be a base class and the call() is virtual, with the derived classes implementing the details as appropriate. Adapt to your situation.

Then export CPlusCallback and SomeObj to Lua, then you can do in Lua:

somObj = SomeObj:Create()

function MyClass:Enter()
    -- creates Lua instance of CPlusClass, with a user data for the C++
    -- counterpart as member
    self.CPlusClass = CPlusClass:Create()  
    self.CPlusCallback = CPlusCallback:Create(someObj, someObj.method)
    self.CPlusClass:RegisterCallback(15, self.CPlusCallback)
end

where the above assumes that someObj.method is a method you exported, from C++ class SomeObj, with the proper signature void (SomeObj::*Method)().