提问人: 提问时间:8/11/2023 更新时间:8/12/2023 访问量:29
传递既不带虚拟继承也不带模板的非静态成员函数 [duplicate]
pass non-static member function with neither virtual inheritance nor templates [duplicate]
问:
如何将对象的非静态成员函数传递给对象?eval
Problem1 obj
Solver solver
#include<iostream>
#include<functional>
// non-templated class
struct Solver{
std::function<void(double&, double&)>* f;
double solve(){
double y,x=1;
for(long int i=0;i<10000;++i){
(*f)(y,x); (*f)(x,y);
}
return y;
}
};
// non-static class; unknown at implementation time of Solver
struct Problem1{
double p;
void eval(double& y, double& x){
y = x*x - p;
}
};
int main(){
Problem1 obj;
Solver solver;
solver.f = &(obj.eval); // pass non-static member function
solver.solve();
}
由于一个求解器将用于求解各种问题类的许多不同实例,因此我不想使用模板。由于一个问题对象的解决可能需要非常多的调用,由于 c++ 中虚拟类的开销和缓慢的声誉,我不敢使用来自类的虚拟继承。这在这里重要吗?我该怎么办?eval
VirtualProblem
答:
2赞
Some programmer dude
8/11/2023
#1
但事实并非如此。std::function
首先,它不应该是一个指针。不能将指向非静态成员函数的指针分配给它(尤其是不能为其指针)。而且你不能以这种方式使用非静态成员函数。
为了解决你的问题,首先让我们创建一个非指针对象:f
struct Solver{
std::function<void(double&, double&)> f;
double solve(){
double y,x=1;
for(long int i=0;i<10000;++i){
f(y,x); f(x,y);
}
return y;
}
};
然后我们可以使用 lambda 在正确的对象上调用正确的函数:
solver.f = [&obj](double& a, double& b)
{
obj.eval(a, b);
};
另一方面,如果你想从函数返回一个值,实际上是一个值。请不要在不需要的时候滥用引用参数。return
评论
0赞
8/12/2023
感谢您的帮助!关于返回值注释:我这样做是因为这是一个最小的例子。也许,在传递 nD 数组时,您会同意引用/指针更好。
0赞
8/12/2023
哦,我刚刚注意到:您建议的带有绑定的代码在 GNU g++ 12.0.1 中产生以下编译器错误: mini_main.cpp:27:92:错误:'operator=' 不匹配(操作数类型为 'std::function<void(double&, double&>)' 和 'std::_Bind_helper<false, Problem1&, void (Problem1::*)(double&, double&), const std::_Placeholder<1>&, const std::_Placeholder<2>&>::type') @Some-programmer-dude 你知道如何解决这个问题吗?
0赞
Some programmer dude
8/12/2023
@DarikaRanganathan嗯,这很奇怪,我以为我测试了它,它确实有效,但不是它没有。也许我在幻觉...... :-)无论如何,我从答案中删除了该选项。
0赞
Some programmer dude
8/12/2023
@DarikaRanganathan 关于返回问题,如果你的要求是就地修改第一个参数(值、数组等),则通过引用传递它,对于简单值,按值传递第二个参数,否则通过常量引用传递它。如果没有就地要求,那么即使对于数组和对象,我仍然建议返回 n 个实际值(或对象)。您仍然可以返回一个值/对象,并赋值回用于第一个参数的变量。编译器可以为你创建非常好的优化代码,所以不要想太多。
0赞
Misha T
8/11/2023
#2
I think, you could use 'std::bind'
评论
(1)
创建空对象,因此通常不需要使用指向对象的指针。std::function
std::function
std::function
也会有开销。的开销并不大,通常在调用函数时会增加几个级别的间接性。实现需要跟随指向表的指针,然后在该表中查找函数指针。我不确定开销是多少,但它可能处于相同的数量级。由于您正在尝试保存指向函数的指针并通过它调用函数,因此您从一开始就已经有了一定程度的间接性。virtual
vtable
std::function
double solve(const std::function<void(double,double)> f) { ... }
solver.solve(obj.eval);
)