Передать указатель на функцию-член в C ++ - PullRequest
2 голосов
/ 23 ноября 2010

Я пытаюсь передать указатель на функцию (типа QScriptEngine::FunctionSignature (= QScriptValue (QScriptContext *, QScriptEngine *))) другой функции.Но функция, которую мне нужно передать, является функцией-членом класса.

Я использую ее следующим образом:

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

В этом примере я получаю сообщение об ошибке:

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

Как передать функцию печати в newFunction?

РЕДАКТИРОВАТЬ:

Я исправил это так:

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

Ответы [ 4 ]

1 голос
/ 23 ноября 2010

Это не работает, потому что функция не является методом, и поэтому сигнатура отличается. В отличие от других языков, в C ++ метод не привязан к объекту, поэтому он является сигнатурой метода и должен применяться к объекту.

Что вам нужно сделать, это обернуть правильную функцию (или статическую) с хорошей сигнатурой и вызвать нужный метод для объекта, переданного как аргумент.

как

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.

}

Возможно, вы хотели бы вместо этого передать your_class как атрибут контекста, а не как движок, но это идея. Вам нужна статическая оболочка для вашего метода с где-то в аргументе объектом, чтобы применить к нему вашу функцию.

0 голосов
/ 23 ноября 2010

К сожалению, в C ++ нет способа передать функцию-член, где ожидается обычный указатель на функцию. Указатель на функцию-член НЕ является указателем на функцию и может использоваться только в сочетании с указателем на объект.

Вам нужно написать статическую функцию и получить указатель на ваш объект MyClass из «другого места»:

  1. Может быть, есть способ сохранить указатель на ваш объект в каком-то поле «пользовательских данных» или «контекста» объектов QScriptEngine или QScriptContext, которые будут переданы вашей функции? Прочтите документацию, чтобы узнать, были ли разработчики Qt вам милы.

  2. Используйте глобальную std :: map, чтобы связать один из ваших объектов MyClass с каждым QScriptEngine.

  3. Если вы заботитесь о производительности, не заботитесь о переносимости, знаете, что такое соглашение о вызовах, взгляните на библиотеку libffi с открытым исходным кодом (http://sourceware.org/libffi/),, которая позволяет создавать указатели функций во время выполнения. Для вашего среднего приложения Qt это слишком много.

0 голосов
/ 23 ноября 2010

Проблема, с которой вы можете столкнуться при простой передаче ссылки на функцию-член, состоит в том, что функции-члену необходим экземпляр объекта для выполнения.Если это так, взгляните на Boost.bind, в частности, this part .Предполагая, что вы хотите использовать метод print () для текущего объекта вашего типа MyClass, вы можете захотеть что-то вроде этого:

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

Это, вероятно, заставит вас немного переделать setProperty ().

0 голосов
/ 23 ноября 2010

Попробуйте указать идентификатор:

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

РЕДАКТИРОВАТЬ:

Как я вижу объявление функции, вы должны использовать boost::bind, как другие предложенные:

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

boost::bind преобразует метод и вызываемый объект (this) в объект, который может вызывать этот метод для объекта.

...