V8 Экземпляр класса FunctionTemplate - PullRequest
8 голосов
/ 03 июля 2010

У меня есть следующий класс:

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

Я хочу, чтобы метод Register был доступен из JavaScript. Я добавляю его к глобальному объекту так:

PluginManager pluginManagerInstance;

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

Выдает следующую ошибку:

'PluginManager :: Register': функция вызвать список отсутствующих аргументов; использование '& PluginManager :: Register' для создания указатель на член

Я пытался это сделать, но это тоже не сработало. И это не правильно, потому что я хочу, чтобы он вызывал метод Register для pluginManagerInstance .

За исключением идеи статического или глобального метода Register, есть идеи?

Спасибо.

Ответы [ 4 ]

7 голосов
/ 06 июля 2010

Вы пытаетесь связать две вещи одновременно: экземпляр и метод, чтобы вызвать его, и он будет выглядеть как указатель на функцию. К сожалению, это не работает в C ++. Вы можете привязать указатель только к простой функции или к методу static . Итак, вы добавляете статический метод «RegisterCB» и регистрируете его в качестве обратного вызова:

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

Теперь, откуда вы взяли pluginManagerInstance? Для этого большинство API-интерфейсов регистрации обратного вызова в V8 имеют дополнительный параметр «data», который будет возвращен обратному вызову. Как и FunctionTemplate :: New. Итак, вы действительно хотите связать это так:

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

Затем данные доступны через args.Data (), и вы можете делегировать их фактическому методу:

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

Конечно, это можно сделать немного проще с помощью некоторого макроса.

2 голосов
/ 23 августа 2012

Для примера взгляните на код в этого урока .Тот же метод, который предлагает выше предложенный mernst, используется для отправки указателя на этот объект в функцию журнала.

в заголовке:

    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;
    }

реализация:

////////////////////////////////////////////////////////////////////////
//
// 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();
}
2 голосов
/ 03 июля 2010

Скорее всего, вам нужно сделать его статичным. Не забывайте, что функции-члены скрывают этот параметр в качестве первого аргумента. Из-за этого они редко работают как прототипы указателей на функции.

0 голосов
/ 03 июля 2010

Если вы хотите вызвать этот метод, вы должны добавить круглые скобки:

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

Если вы хотите взять егоадрес , вы должны добавить &:

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

(это именно то, что говорится в сообщении об ошибке.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...