【问题标题】:V8 FunctionTemplate Class InstanceV8 FunctionTemplate 类实例
【发布时间】:2012-10-02 01:41:36
【问题描述】:

我有以下课程:

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

我希望可以从 JavaScript 访问 Register 方法。我像这样将它添加到全局对象中:

PluginManager pluginManagerInstance;

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

它会抛出以下错误:

'PluginManager::Register': 函数 调用缺少的参数列表;利用 '&PluginManager::Register' 创建一个 指向成员的指针

我试图这样做,但它也不起作用。而且不正确,因为我希望它调用pluginManagerInstance的Register方法。

除了将 Register 方法设为静态或全局之外,还有什么想法吗?

谢谢。

【问题讨论】:

    标签: c++ static instance v8


    【解决方案1】:

    你试图一次绑定两个东西:实例和调用它的方法,让它看起来像一个函数指针。不幸的是,这在 C++ 中不起作用。您只能将指针绑定到普通函数或 static 方法。因此,您添加一个静态“RegisterCB”方法并将其注册为回调:

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

    现在你从哪里得到 pluginManagerInstance?为此,V8 中的大多数回调注册 API 都有一个额外的“数据”参数,该参数将被传递回回调。 FunctionTemplate::New 也是如此。所以你实际上想像这样绑定它:

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

    然后可以通过 args.Data() 获得数据,您可以委托给实际方法:

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

    这肯定可以通过一些宏来简化一些。

    【讨论】:

      【解决方案2】:

      您可能需要将其设为静态。不要忘记成员函数将隐藏的 this 参数作为第一个参数。因此,它们很少能很好地用作函数指针原型。

      【讨论】:

        【解决方案3】:

        例如,查看this tutorial 中的代码。上面 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();
        }
        

        【讨论】:

        • 谢谢,这对我帮助很大。
        【解决方案4】:

        如果你想调用那个方法,你必须加括号:

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

        如果你想获取它的地址,你必须添加一个&amp;

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

        (这正是错误消息所说的内容。)

        【讨论】:

        • 由于这被否决了,这似乎有问题。它有什么错的?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-06-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多