我想解决有关类成员函数回调的这个问题。 想象一下,你有一个来自外部库(无法修改!)的函数,如下所示:
void fortranFunction(int n, void udf(double*) );
我想将udf函数作为现有类的函数成员传递。请查看以下代码:
// External function (tipically from a fortran library)
void fortranFunction(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
fortranFunction(n, myUDF);
// The UDF is the classUDF member function of a myClass object
myClass myClassObj;
fortranFunction(n, myClassObj.classUDF); // ERROR!!
}
上面代码的最后一行导致编译错误,因为您无法将classUDF成员函数声明为静态函数。 你知道是否有可能解决这个问题? 可能Boost库可以帮助我,但我不知道如何(请考虑fortranFunction无法修改,因为来自外部库)。 非常感谢! 阿尔贝托
答案 0 :(得分:0)
我不明白,为什么你不能像这样classUDF
宣布static
class myClass {
public:
static void classUDF(double *a) {
...
}
};
然后传递它
fortranFunction(n, myClass::classUDF);
答案 1 :(得分:0)
你可能会尝试这个解决方案(有点hacky,但我想,它应该适合你):
void fortranFunction(int n, void udf(double*))
{
double d = static_cast<double>(n);
udf(&d);
}
class myClass {
public:
void classUDF(double* a) {
}
};
#ifdef _MSC_VER
#define THREADLOCALSTATIC __declspec(thread) static
#define THREADLOCAL
#else
#define THREADLOCALSTATIC static ___thread
#define THREADLOCAL ___thread
#endif
struct _trampolinebase {
THREADLOCALSTATIC _trampolinebase* current_trampoline;
};
THREADLOCAL _trampolinebase* _trampolinebase::current_trampoline = 0;
#undef THREADLOCAL
#undef THREADLOCALSTATIC
template<class CBRET, class CBARG1, class T>
struct _trampoline1 : _trampolinebase
{
typedef CBRET (T::*CALLBACKFN)(CBARG1);
_trampoline1(T& target, CALLBACKFN& callback)
: callback_(callback)
, target_(target)
{
assert(current_trampoline == 0);
current_trampoline = this;
}
static CBRET callback(CBARG1 a1) {
_trampoline1* this_ = static_cast<_trampoline1*>(current_trampoline);
current_trampoline = 0;
return this_->trampoline(a1);
}
private:
CBRET trampoline(CBARG1 a1) {
return (target_.*callback_)(a1);
}
CALLBACKFN& callback_;
T& target_;
};
template<class FRET, class FARG1, class CBRET, class CBARG1, class T, class F>
FRET call1_1(T& target, CBRET (T::*callback)(CBARG1), F& fortranfunction, FARG1 a)
{
typedef typename _trampoline1<CBRET, CBARG1, T> trampoline;
trampoline t(target, callback);
return fortranFunction(a, trampoline::callback);
}
int main()
{
int n=1;
myClass myClassObj;
call1_1<void,int,void,double*>(myClassObj, &myClass::classUDF, fortranFunction, 1);
}
使用'threadlocal'的东西,这也适用于多线程调用。如果不使用多线程环境,则可以省略它。它也适用于递归调用(例如,如果回调调用另一个fortran函数)。
此解决方案仅适用于一个参数加上fortran函数的回调和回调函数本身的一个参数,但您应该能够轻松扩展它。这也是,为什么我称之为'call1_1'(带有1个参数的fortran函数,带有1个参数的callbackfunction)。 FRET是fortran函数的返回类型,FARG1是第一个参数的类型(在本例中为int)。 CBRET和CBARG与回调函数相同。
在实际调用fortran函数之前,目标对象存储在全局(线程局部)变量中。 fortran函数调用静态回调函数,最终调用你的成员函数。
我发明了trampolinebase来实例化静态成员,我也可以使用全局变量(但出于某种原因,我不太喜欢全局变量); - )