2010-07-03 25 views
7

tengo la clase siguiente:V8 FunctionTemplate Clase Instancia

class PluginManager 
{ 
public: 
    Handle<Value> Register(const Arguments& args); 
    Handle<ObjectTemplate> GetObjectTemplate(); 
}; 

Quiero que el método de Registro para ser accesible desde JavaScript. Lo añado al objeto global como esto:

PluginManager pluginManagerInstance; 

global->Set(String::New("register"), FunctionTemplate::New(pluginManagerInstance.Register)); 

que arroja el siguiente error:

'PluginManager::Register': function call missing argument list; use '&PluginManager::Register' to create a pointer to member

he tratado de hacer eso, pero no funciona bien. Y no es correcto, porque quiero que llame al método Register del pluginManagerInstance.

Excepto por hacer que el método de registro sea estático o global, ¿alguna idea?

Gracias.

Respuesta

5

Está intentando unir dos cosas a la vez: la instancia y el método para invocar sobre ella, y hacer que se vea como un puntero de función. Desafortunadamente, eso no funciona en C++. Solo puede enlazar un puntero a una función simple o un método estático. Así imagen que añadir un método estático "RegisterCB" y registrarlo como la devolución de llamada:

static Handle<Value> RegisterCB(const Arguments& args); 
...FunctionTemplate::New(&PluginManager::RegisterCB)... 

Ahora ¿de dónde sacas el pluginManagerInstance de? Para este propósito, la mayoría de las aplicaciones de registro de devolución de llamada en V8 tienen un parámetro de "datos" adicional que pasará a la devolución de llamada. Lo mismo ocurre con FunctionTemplate :: New. Lo que en realidad desea enlazar así:

...FunctionTemplate::New(&PluginManager::RegisterCB, 
         External::Wrap(pluginManagerInstance))... 

, los datos estarán disponibles a través de args.Data() y se puede delegar en el método actual:

return ((PluginManager*)External::Unwrap(args.Data())->Register(args); 

Sin duda, esto se puede hacer una poco más fácil con algunos macro.

2

Es probable que necesite hacerlo estático. No olvides que las funciones de miembro ocultan este parámetro como primer argumento. Debido a esto, raramente funcionan bien como prototipos de punteros de función.

0

Si desea llamada ese método, hay que añadir paréntesis:

lobal->Set(String::New("register") 
      , FunctionTemplate::New(pluginManagerInstance.Register())); 
                   ^^ 

Si desea tomar su dirección, hay que añadir un &:

lobal->Set(String::New("register") 
      , FunctionTemplate::New(&PluginManager::Register)); 
           ^

(Que es exactamente lo que dice el mensaje de error.)

+0

Dado que esta se había reducido votaron, parece que hay algo mal con esto. ¿Qué tiene de malo? – sbi

2

Por ejemplo, eche un vistazo al código en this tutorial. El mismo método que mernst sugiere más arriba se usa para enviar un puntero a este objeto, a la función de registro.

en la cabecera:

virtual void log(const string &str); 
    static Handle<Value> logCallback(const Arguments &args); 

    Local<FunctionTemplate> makeStaticCallableFunc(InvocationCallback func); 
    Local<External> classPtrToExternal(); 

    //////////////////////////////////////////////////////////////////////// 
    // 
    // Converts an External to a V8TutorialBase pointer. This assumes that the 
    // data inside the v8::External is a "this" pointer that was wrapped by 
    // makeStaticCallableFunc 
    // 
    // \parameter data Shoudld be v8::Arguments::Data() 
    // 
    // \return "this" pointer inside v8::Arguments::Data() on success, NULL otherwise 
    // 
    ////////////////////////////////////////////////////////////////////////   
    template <typename T> 
    static T *externalToClassPtr(Local<Value> data) 
    { 
     if(data.IsEmpty()) 
      cout<<"Data empty"<<endl; 
     else if(!data->IsExternal()) 
      cout<<"Data not external"<<endl; 
     else 
      return static_cast<T *>(External::Unwrap(data)); 

     //If function gets here, one of the checks above failed 
     return NULL; 
    } 

aplicación:

//////////////////////////////////////////////////////////////////////// 
// 
// Wrap a callback function into a FunctionTemplate, providing the "this" 
// pointer to the callback when v8 calls the callback func 
// 
// \parameter func Static callback to be used in FunctionTemplate 
// 
// \return Local<FunctionTemplate> containing func 
// 
//////////////////////////////////////////////////////////////////////// 
Local<FunctionTemplate> V8TutorialBase::makeStaticCallableFunc(InvocationCallback func) 
{ 
    HandleScope scope; 
    Local<FunctionTemplate> funcTemplate = FunctionTemplate::New(func, classPtrToExternal()); 
    return scope.Close(funcTemplate); 
} 

//////////////////////////////////////////////////////////////////////// 
// 
// Makes the "this" pointer be an external so that it can be accessed by 
// the static callback functions 
// 
// \return Local<External> containing the "this" pointer 
//////////////////////////////////////////////////////////////////////// 
Local<External> V8TutorialBase::classPtrToExternal() 
{ 
    HandleScope scope; 
    return scope.Close(External::New(reinterpret_cast<void *>(this))); 
} 

Handle<Value> V8TutorialBase::logCallback(const Arguments &args) 
{ 
    HandleScope scope; 

    ..... 

    V8TutorialBase *objPtr = externalToClassPtr<V8TutorialBase>(args.Data()); 
    String::Utf8Value val(Local<String>::Cast(args[0])); 
    objPtr->log(*val); // log is a non static member function 
    // or you can directly do anything that you would do in a member function using the objPtr 

    return v8::Null(); 
} 
+0

Gracias, eso me ayudó mucho. – danijar

Cuestiones relacionadas