Обратный вызов функции-члена класса C ++ - PullRequest
2 голосов
/ 10 ноября 2011

У меня следующая проблема. У меня есть функция из внешней библиотеки (которая не может быть изменена), как это:

void externalFunction(int n, void udf(double*) );

Я хотел бы передать как функцию udf над функцией-членом существующего класса. Пожалуйста, посмотрите на следующий код:

// External function (tipically from an external library)
void externalFunction(int n, void udf(double*) )
{
     // do something
}

// User Defined Function (UDF)
void myUDF(double* a)
{
      // do something
}

// Class containing the User Defined Function (UDF)
class myClass
{
public:
    void classUDF(double* a)
    {
        // do something...
    };
};

int main()
{
    int     n=1;

    // The UDF to be supplied is myUDF
    externalFunction(n, myUDF);

    // The UDF is the classUDF member function of a myClass object
    myClass myClassObj;
    externalFunction(n, myClassObj.classUDF);   // ERROR!!
}

Я не могу объявить функцию-член classUDF как статическую функцию, поэтому последняя строка кода выше приводит к ошибке компиляции!

Ответы [ 3 ]

6 голосов
/ 10 ноября 2011

Это невозможно сделать - в c ++ вы должны использовать либо свободную функцию, либо статическую функцию-член, либо (в c ++ 11) лямбду без захвата, чтобы получить указатель на функцию.

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

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

Так что, если вы в порядке с нереенерируемой функцией, создайте глобальную / статическую переменную, которая будет указывать на this, и используйте ее в вашей статической функции.

class myClass
{
public:
    static myClass* callback_this;
    static void classUDF(double* a)
    {
        callback_this.realUDF(a);
    };
};

Это действительно ужасный код, но, боюсь, вам не повезло с таким плохим дизайном, как ваш externalFunction.

5 голосов
/ 10 ноября 2011

Вы можете использовать Boost bind или TR1 bind (на последних компиляторах) ;;

externalFunction(n, boost::bind(&myClass::classUDF, boost::ref(myClassObj)));

К сожалению, я жил внесбыточная мечта за последние 10 минут.Единственный способ продвинуться вперед - это вызвать цель, используя некую статическую функцию-обертку.Другие ответы имеют различные аккуратные (специфичные для компилятора) лакомые кусочки, но вот главный трюк:

void externalFunction(int n, void (*udf)(double*) )
{ double x; udf(&x); }

myClass myClassObj;
void wrapper(double* d) { myClassObj.classUDF(d); }

int main()
{
    externalFunction(1, &wrapper);
}

std :: function <>

Сохранение связанной функции в переменной, напримерэто:

std::function<void(double*)> stored = std::bind(&myClass::classUDF, boost::ref(myClassObj))

(при условии поддержки C ++ 0x в компиляторе. Я уверен, что Boost имеет boost :: function <> где-то)

Указатели Vanilla C ++ на член-функция

Без такой магии вам понадобится указатель на член функции синтаксис:

Смотрите также в прямом эфире на http://ideone.com/Ld7It

Изменить , чтобы уточнить для комментаторов, очевидно, это работает только если у вас есть контроль над определением externalFunction.Это является прямым ответом на / broken / snippet int OP.

struct myClass
{
    void classUDF(double* a) { };
};

void externalFunction(int n, void (myClass::*udf)(double*) )
{
    myClass myClassObj;
    double x;
    (myClassObj.*udf)(&x); 
}

int main()
{
    externalFunction(1, &myClass::classUDF);
}

C ++ 98 идиоматическое решение

// mem_fun_ref example
#include <iostream>
#include <functional>
#include <vector>
#include <algorithm>
#include <string>

int main () 
{
    std::vector<std::string> numbers;

    // populate vector:
    numbers.push_back("one");
    numbers.push_back("two");
    numbers.push_back("three");
    numbers.push_back("four");
    numbers.push_back("five");

    std::vector <int> lengths (numbers.size());

    std::transform (numbers.begin(), numbers.end(), lengths.begin(), 
                std::mem_fun_ref(&std::string::length));

    for (int i=0; i<5; i++) {
        std::cout << numbers[i] << " has " << lengths[i] << " letters.\n";
    }
    return 0;
}
2 голосов
/ 10 ноября 2011

Вот как я это делаю, когда MyClass является синглтоном:

void externalFunction(int n, void udf(double) );

class MyClass
{
public:
   static MyClass* m_this;
   MyClass(){ m_this = this; }
   static void mycallback(double* x){ m_this->myrealcallback(x); }
   void myrealcallback(double* x);
}

int main()
{
   MyClass myClass;
   externalFunction(0, MyClass::mycallback);
}
...