2010-04-22 4 views
11

Ho una funzione C (A) test_callback accettare un puntatore a una funzione (B) come parametro e una volontà "callback" B.come callback una funzione lua dalla funzione 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 

Ora, Voglio avvolgere test_callback in modo che possano essere chiamati da lua, supponiamo che il nome sia lua_test_callback e che il parametro di input sia una funzione lua. Come devo raggiungere questo obiettivo?

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 forniscono un modo per memorizzare la funzione di callback per un uso successivo.

//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 

risposta

9

io non sono sicuro di aver capito la tua domanda, se ti stai chiedendo cosa sarebbe lua_test_callback sguardo in C, dovrebbe essere qualcosa di simile

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 
} 

Non si può semplicemente avvolgere test_callback, è necessario tutto implementazione diversa per chiamare le funzioni Lua.

(edit: cambiato lua_call-lua_pcall come suggerito da Nick ho ancora omesso qualsiasi trattamento per brevità errore).

+2

È preferibile utilizzare lua_pcall che spingerà un errore nello stack piuttosto che schiantarsi. –

+0

Bel esempio corretto. Ma in pratica è meglio usare un'interfaccia comune e ben testata, nonostante la scrittura di tali funzioni lua_test_callback() ancora e ancora. –

3

Il modo comodo di fare chiamate a funzioni diverse Lua con firme diverse:

A. Effettuare una classe che manterrà lo stato di Lua in sicurezza e fornirà un'interfaccia semplice. Non scrivere chiamate alle funzioni Lua da zero (con molto lavoro push/pop e asserzioni) ancora e ancora: basta usare questa interfaccia di classe. Questo è un approccio sicuro, veloce e conveniente.

B. Definire push e pop metodi per spingere/argomenti pop sul/dal Lua pila:

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. definire funzioni di chiamare funzioni 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. Imposta gestore errori (lua_pcall chiamerà questa funzione Lua se errore)

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