传递既不带虚拟继承也不带模板的非静态成员函数 [duplicate]

pass non-static member function with neither virtual inheritance nor templates [duplicate]

提问人: 提问时间:8/11/2023 更新时间:8/12/2023 访问量:29

问:

如何将对象的非静态成员函数传递给对象?evalProblem1 objSolver 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++ 中虚拟类的开销和缓慢的声誉,我不敢使用来自类的虚拟继承。这在这里重要吗?我该怎么办?evalVirtualProblem

C++ 模板 函数指 指向成员 的指针 虚拟继承

评论

0赞 fabian 8/11/2023
不相关:您可以使用构造函数签名 (1) 创建空对象,因此通常不需要使用指向对象的指针。std::functionstd::function
1赞 François Andrieux 8/11/2023
std::function也会有开销。的开销并不大,通常在调用函数时会增加几个级别的间接性。实现需要跟随指向表的指针,然后在该表中查找函数指针。我不确定开销是多少,但它可能处于相同的数量级。由于您正在尝试保存指向函数的指针并通过它调用函数,因此您从一开始就已经有了一定程度的间接性。virtualvtablestd::function
0赞 OrenIshShalom 8/11/2023
旁注:可能会更好一点(有double solve(const std::function<void(double,double)> f) { ... }solver.solve(obj.eval);)

答:

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'