2010-04-22 17 views
11

Tengo una función C (A) test_callback aceptar un puntero a una función (B) como el parámetro y A se "devolución de llamada" B.cómo devolución de llamada una función lua de función ac

//typedef int(*data_callback_t)(int i); 
int test_callback(data_callback_t f) 
{ 
    f(3); 
} 


int datacallback(int a) 
{ 
    printf("called back %d\n",a); 
    return 0; 
} 


//example 
test_callback(datacallback); // print : called back 3 

Ahora, Quiero envolver test_callback para que puedan ser llamados desde lua, supongo que el nombre es lua_test_callback; y también el parámetro de entrada a la que sería una función Lua. ¿Cómo debería lograr este objetivo?

function lua_datacallback (a) 
    print "hey , this is callback in lua" ..a 
end 


lua_test_callback(lua_datacallback) //expect to get "hey this is callback in lua 3 " 

EDIT:

This link proporcionan una manera de almacenar la función de devolución de llamada para su uso posterior.

//save function for later use 
callback_function = luaL_ref(L,LUA_REGISTRYINDEX); 


//retrive function and call it 
lua_rawgeti(L,LUA_REGISTRYINDEX,callback_function); 
//push the parameters and call it 
lua_pushnumber(L, 5); // push first argument to the function 
lua_pcall(L, 1, 0, 0); // call a function with one argument and no return values 

Respuesta

9

No estoy seguro de entender su pregunta, si está pidiendo lo que sería lua_test_callback mirada en C, que debe ser algo como esto

int lua_test_callback(lua_State* lua) 
{ 
    if (lua_gettop(lua) == 1 && // make sure exactly one argument is passed 
     lua_isfunction(lua, -1)) // and that argument (which is on top of the stack) is a function 
    { 
     lua_pushnumber(lua, 3); // push first argument to the function 
     lua_pcall(lua, 1, 0, 0); // call a function with one argument and no return values 
    } 
    return 0; // no values are returned from this function 
} 

No se puede envolver test_callback, necesita su totalidad implementación diferente para llamar funciones Lua.

(edit: cambiado lua_call-lua_pcall como se sugiere por Nick Todavía omitido cualquier manipulación por razones de brevedad de error.)

+2

Es preferible utilizar lua_pcall lo que empujará un error en la pila en lugar de sólo estrellarse. –

+0

Buen ejemplo correcto. Sin embargo, en la práctica, es mejor usar interfaz común, bien probado, a pesar de escribir tales lua_test_callback() funciona una y otra vez. –

3

La forma más conveniente de hacer llamadas a diferentes funciones Lua con diferentes firmas:

A. Hacer una clase que mantendrá el estado de Lua de forma segura y proporcionará una interfaz sencilla. No escriba las llamadas a funciones Lua desde cero (con una gran cantidad de trabajo de empuje/pop y afirma) una y otra vez - sólo tiene que utilizar esta interfaz clase. Este es un enfoque seguro, rápido y conveniente.

B. Definir empuje y pop métodos para empujar/argumentos POP en/desde Lua apilar:

template<typename T> void push(T argument); 
template<typename T> void get(const int index, T& return_value); 

template<> void State::push(bool arg) 
{ 
    lua_pushboolean (lua_state, arg ? 1 : 0); 
} 

template<> void State::push(float arg) 
{ 
    lua_pushnumber (lua_state, arg); 
} 

template<> void State::push(int arg) 
{ 
    lua_pushnumber (lua_state, arg); 
} 

// ... 
template<> void State::get(const int index, bool& ret) 
{ 
     if (!lua_isboolean(lua_state, index)) { ... } 
     ret = lua_toboolean(lua_state, index) != 0; 
} 

C. definir funciones para llamar a funciones Lua:

// Call function that takes 1 argument and returns nothing 
template <typename A1> 
void call(const char * funcName, A1 arg1) 
{ 
    lua_getfield (lua_state, LUA_GLOBALSINDEX, funcName);  // push global function f on stack 
    push (arg1);           // push first argument on stack 
    assert_call( lua_pcall(lua_state, 1, 0, this->err_h));  // call function taking 1 argument and getting no return value 
} 


// call function that takes 2 argument and returns 1 value 
template <typename R1, typename A1, typename A2> 
void callr1(const char * funcName, R1& res, A1 arg1, A2 arg2) 
{ 
    lua_getfield (lua_state, LUA_GLOBALSINDEX, funcName);  // push global function f on stack 
    push (arg1);           // push first argument on stack 
    push (arg2); 
    assert_call( lua_pcall(lua_state, 2, 1, this->err_h));  // call function taking 2 arguments and getting 1 return value 
    get (-1, res); 
    lua_pop(lua_state, 1); 
} 

D. Conjunto gestor de errores (lua_pcall va a llamar a esta función Lua si el error)

void setErrorHandler(const char * funcName) 
{ 
    lua_getfield (lua_state, LUA_GLOBALSINDEX, funcName); 
    this->err_h = lua_gettop(lua_state); 
} 
Cuestiones relacionadas