将成员函数指针传递给无类函数
在下面的代码中,我无法找出将成员函数传递给通用根查找器的方法。
#include <stdio.h>
double OneDimBisector(double (*fun)(float), float a, float b, float tol){
double val;
val = (*fun)(0.5*(b-a)); // actually: do proper bisection
return val;
}
class EOS {
public:
double S_array[10][10]; // actually: filled by constructor
double S(double T, double P);
double T_PS(double P, double S);
double functForT_PS(double T);
double (EOS::*pfunctForT_PS)(double);
double Sseek, Pseek;
};
double EOS::S(double T, double P){
double val = T+P; // actually: interpolate in S_array
return val;
}
double EOS::functForT_PS(double T){
return S(T,Pseek)-Sseek;
}
// Find T from P and S (T is invertible), assuming the intervals are ok
double EOS::T_PS(double P, double S0){
double Tmin = 2., Tmax = 7., T1, tol=1e-8;
pfunctForT_PS = &EOS::functForT_PS;
Sseek = S0;
Pseek = P;
printf("\n %f\n", (*this.*pfunctForT_PS)(4.)); // no problem
T1 = OneDimBisector(pfunctForT_PS, Tmin, Tmax, tol); // wrong type for pfunctForT_PS
return T1;
}
int main() {
double P=3., S=8;
EOS myEOS;
printf("\n %f %f %f\n",P,S,myEOS.T_PS(P,S));
}
我不想让根查找器成为成员,因为它不是特定于此类的,并且将所有内容设为静态的解决方案似乎非常不优雅。有人有主意吗?这一定是一个常见的情况,但我没有找到我也能理解的相关帖子。
谢谢!
编辑:实际上,我还想问:除了我所做的之外,是否有正确的、线程安全的方法来设置 Pseek
变量?只是为了澄清:我正在二维函数上进行一维根查找,但修复了两个参数之一。
In the code below, I cannot figure out a way of passing a member function to a generic root-finder.
#include <stdio.h>
double OneDimBisector(double (*fun)(float), float a, float b, float tol){
double val;
val = (*fun)(0.5*(b-a)); // actually: do proper bisection
return val;
}
class EOS {
public:
double S_array[10][10]; // actually: filled by constructor
double S(double T, double P);
double T_PS(double P, double S);
double functForT_PS(double T);
double (EOS::*pfunctForT_PS)(double);
double Sseek, Pseek;
};
double EOS::S(double T, double P){
double val = T+P; // actually: interpolate in S_array
return val;
}
double EOS::functForT_PS(double T){
return S(T,Pseek)-Sseek;
}
// Find T from P and S (T is invertible), assuming the intervals are ok
double EOS::T_PS(double P, double S0){
double Tmin = 2., Tmax = 7., T1, tol=1e-8;
pfunctForT_PS = &EOS::functForT_PS;
Sseek = S0;
Pseek = P;
printf("\n %f\n", (*this.*pfunctForT_PS)(4.)); // no problem
T1 = OneDimBisector(pfunctForT_PS, Tmin, Tmax, tol); // wrong type for pfunctForT_PS
return T1;
}
int main() {
double P=3., S=8;
EOS myEOS;
printf("\n %f %f %f\n",P,S,myEOS.T_PS(P,S));
}
I do not want to make the root-finder a member because it is not specific to this class, and the solution of making everything static
seems very inelegant. Would someone have an idea? This must be a common situation yet I did not find a relevant post that was also understandable to me.
Thanks!
Edit: Actually, I also meant to ask: Is there a proper, thread-safe way of setting the Pseek
variable other than what I did? Just to make it clear: I am doing one-dimensional root finding on a two-dimensional function but fixing one of the two arguments.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
一种方法是更改根查找器的签名(添加
#include
):然后使用
bind
调用它:这会带来一定的开销。如果您不介意有大量重复代码,则可以将该函数设为模板:以
相同的方式调用它,但每次有新的函数类型时,都会在编译中创建模板的新实例。
“传统”解决方案是拥有一个接受附加实例参数的自由(或静态)函数。
更新:“传统解决方案”:
用法:
T1 = OneDimBisector(EOSBisect, this, Tmin, Tmax, tol);
One way would be to change the signature of the root finder (add
#include <functional>
):Then invoke it with
bind
:This carries a certain overhead. If you don't mind having lots of duplicate code, you can make the function a template:
You invoke it the same way, but every time you have a new function type, a new instance of the template is created in your compilate.
The "traditional" solution would be to have a free (or static) function that accepts an additional instance argument.
Update: The "traditional solution":
Usage:
T1 = OneDimBisector(EOSBisect, this, Tmin, Tmax, tol);
您不能将成员函数指针作为函数指针传递,因为后者缺少上下文指针(
this
)来正确调用成员函数指针。解决这个问题的一般方法(如在标准 C++ 库中)是使用模板:
并将函数对象传递给它
您也可以使用 std::bind1st(std::mem_fun(&EOS::functForT_PS ), this),但是它的作用和上面的结构是一样的。 (顺便说一句,std::bind1st 和 std::mem_fun 都已被弃用。)
如果您不喜欢模板,您可以接受多态函数(例如使用Boost.Function 或 std::function在 C++11 中),但会更慢:
最后,如果您可以使用 C++11,您可以在调用 OneDimBisector 时使用 lambda 函数:
You cannot pass a member function pointer as a function pointer, because the latter lacks the context pointer (the
this
) to properly invoke the member function pointer.The general way to solve this (as in the standard C++ library) is to use a template:
and pass a function object to it
You could also use
std::bind1st(std::mem_fun(&EOS::functForT_PS), this)
, but what it does is just the same as the structure above. (BTW, both std::bind1st and std::mem_fun have been deprecated.)If you don't like templates, you could accept a polymorphic function instead (e.g. using Boost.Function or std::function in C++11), but it will be slower:
and finally, if you can use C++11, you could use a lambda function on calling OneDimBisector:
您面临的问题是函数指针与成员函数指针不同。
规避该问题的常见(Java 世界)方法是使用策略模式(平分线的乐趣在于策略的某种实现)。
常见的 C++ 方法是使用函子/绑定,例如使用 boost:
The problem you face is that a function pointer is something different to a member funcgtion pointer.
A common (Java World) Approach to circumvent the problem is using the Strategy pattern (fun of the Bisector would be some Implementation of a Strategy).
A common C++-Approach would be using functors/binding, e.g. with boost: