2

I am trying to pass a function pointer (of type QScriptEngine::FunctionSignature (= QScriptValue (QScriptContext *, QScriptEngine *))) to an other function. But the function I need to pass is a member function of a class.

I use it like this:

class MyClass
{
    SomeVarType someVarINeedAccessTo;

    QScriptValue print(QScriptContext* context, QScriptEngine* engine)
    {
        ... someVarINeedAccessTo ...
    }

    void someFunction()
    {
        QScriptEngine engine;
        QScriptValue printFunction = engine.newFunction(print);
        engine.globalObject().setProperty("print", printFunction);
    }
};

With this example I get the error:

error: no matching function for call to QScriptEngine::newFunction(<unresolved overloaded function type>) note: candidates are: ...

How can I pass the print function to newFunction?

EDIT:

I fixed it like this:

class MyClass
{
    public:
         ...

         class TheEngine : public QScriptEngine
         {
             public:
                  MyClass* instance;
         };

         static QScriptValue print(QScriptContext *context, QScriptEngine *engine);

         void someFunction();

         ...
 };

 Myclass::someFunction()
 {
     TheEngine engine;

     ...

     QScriptVaue printFunction = engine.createFunction(print);
     engine.globalObject().setProperty("print", printFunction);

     ...
 }

 QScriptValue MyClass::print(QScriptContext* context, QScriptEngine* engine)
 {
      TheEngine* eng = dynamic_cast<TheEngine*>(engine);
      eng->instance->doSomething(...);
      return engine->undefinedValue();
 }
VDVLeon
  • 1,393
  • 1
  • 15
  • 26
  • The following link might be helpful if you haven't come across it already: http://www.parashift.com/c++-faq-lite/pointers-to-members.html – Tom Nov 23 '10 at 15:33

4 Answers4

1

That doesn't work because a function is not a method and so the signature are different. As opposed to other language, in C++ a method is not bound to an object, so it as the signature of a method and need to be applied on a object.

What you should do is wrap a proper function which (or a static one) with the good signature and call the method you want on the object passed as argumment.

like

MyClass : public QScriptEngine {
  static QScriptValue static_print(QScriptContext* context, QScriptEngine* engine)
  {
    MyClass *my_engine = dynamic_cast<MyClass>(engine)
    my_engine->print(context);
  }

// redefine print to take only one argument.

}

Maybe you would like instead to pass your_class as an attribute of the context rather than being the engine, but that's the idea. You need a static wrapper to your method with somewhere in the argument the object to apply your function on it.

mb14
  • 22,276
  • 7
  • 60
  • 102
  • Is there a way to register c++ function that uses member value which is non `engine`? Like print that uses some external object to redirect input. – Dan M. Oct 18 '16 at 07:47
0

Try qualifying the identifier:

QScriptValue printFunction =
    engine.newFunction(&MyClass::print);

EDIT:

As I see the declaration of the function, you have to use boost::bind as other suggested:

QScriptValue printFunction =
    engine.newFunction(boost::bind(&MyClass::print, this, _1, _2));

boost::bind converts the method and the object to be called (this) into an object that can call that method on the object.

Diego Sevilla
  • 28,636
  • 4
  • 59
  • 87
  • I get `error: no matching function for call to QScriptEngine::newFunction(QScriptValue (MyClass::*)(QScriptContext*, QScriptEngine*))` – VDVLeon Nov 23 '10 at 14:58
  • That means that your `QScriptEngine::newFunction` method is not accepting the correct function signature. What is the definition of that? – Bill Lynch Nov 23 '10 at 15:00
  • Like i posted: `QScriptValue (QScriptContext *, QScriptEngine *)` – VDVLeon Nov 23 '10 at 15:01
  • @VDVLeon: sharth is asking for the signature of the `newFunction` method. – Diego Sevilla Nov 23 '10 at 15:07
  • My bad, srry. But it is: `QScriptValue QScriptEngine::newFunction ( FunctionSignature fun, int length = 0 )` http://doc.qt.nokia.com/4.7/qscriptengine.html#newFunction – VDVLeon Nov 23 '10 at 15:16
  • OK, I changed the response as I see the method declaration. – Diego Sevilla Nov 23 '10 at 15:22
0

The problem you may have with just passing the member function reference is that the member function needs an object instance to execute against. If so, have a look at Boost.bind, in particular, this part. Assuming that you want the print() method to the current object of your MyClass type, you might want something like this:

class MyClass
{
    SomeVarType someVarINeedAccessTo;

    QScriptValue print(QScriptContext* context, QScriptEngine* engine)
    {
        ... someVarINeedAccessTo ...
    }

    void someFunction()
    {
        QScriptEngine engine;
        engine.globalObject().setProperty("print", 
           boost::bind(&MyClass::print, this, _1, _2));
    }
};

This will probably cause you to rework setProperty() a little.

gregg
  • 1,027
  • 5
  • 6
  • setProperty is a function of the Qt library. Not something I want to change the code of... – VDVLeon Nov 23 '10 at 15:14
  • @VDVLeon: Well, that does make it more challenging for me. I don't have much Qt experience. The second parameter to setProperty() is a QVariant so you may be able to convince it to store some kind of reference to the bound function. Looks like you're happy with @mb14's solution so have a nice day! – gregg Nov 23 '10 at 15:54
0

Unfortunately, there is no way in C++ to pass a member function where a regular function pointer is expected. A pointer to a member function is NOT a function pointer, and can only be used in conjunction with an object pointer.

You will have to write a static function and get a pointer to your MyClass object from "somewhere else":

  1. There might be a way to store a pointer to your object into some "user data" or "context" field of the QScriptEngine or QScriptContext objects that will get passed to your function? Read the documentation to find out if the Qt developers were nice to you.

  2. Use a global std::map to associate one of your MyClass objects with each QScriptEngine.

  3. If you care about performance, don't care about portability, know what a calling convention is, have a look at the open-source libffi library (http://sourceware.org/libffi/), which allows you to construct function pointers at runtime. For your average Qt application, this is way overkill.

wolfgang
  • 4,883
  • 22
  • 27