简体   繁体   English

将乘法类的指针传递给成员函数

[英]passing pointer to multiply classes to a member function

I have the next classes:我有以下课程:

"Integrator.h"

#include <vector>
#include <array>
using namespace std;

class Integrator {
public:
    using coord_type = array<double, 3>;  
protected:
    void base_integrate_callback(const coord_type, double t_k) {
      //does nothing
    }
};

class MyIntegrator :public Integrator {
public:
   template <class T>
   void integrate(int mp_id, int t_span, int step ,
   void(T::*callback)(const coord_type, double) = (Integrator::*)(const coord_type, double)){
  //calls callback here
}
};

"main.cpp"

#include Integrator.h"

struct caller {
   void callback(const Integrator::coord_type coord, double t_k) {
   //does smth
}
};

int main(){
   MyIntegrator integrator_1;
   caller A;
   int mp_id = 1;
   int span = 365;
   int step = 1;
   integrator_1.integrate<caller>(mp_id,span,step,&A.callback);
   return 0;
}

Trying to compile it I get an error:尝试编译它我收到一个错误:

file:integration.h, line 18, syntax error: '< tag>::*'文件:integration.h,第 18 行,语法错误:'<标签>::*'

How can I call a callback which could belong to any class?如何调用可能属于任何类的回调?

And the second question: when I try to call it without explicit template specification like第二个问题:当我尝试在没有明确模板规范的情况下调用它时

integrator_1.integrate(mp_id,span,step,&A.callback);

I get an error我收到一个错误

file: main.cpp , line 65, 'MyIntegrator::integrate': no matching overloaded function found文件: main.cpp ,第 65 行,“MyIntegrator::integrate”:未找到匹配的重载函数

So, why this function can not deduce its argument from its parameter?那么,为什么这个函数不能从它的参数推导出它的参数呢?

Also I get the same error when calling it without the last parameter relying on the default parameter.在没有依赖默认参数的最后一个参数的情况下调用它时,我也遇到了同样的错误。

integrator_1.integrate(mp_id,span,step);

Decrypting what you have here with a little indentation用一点缩进解密你在这里的东西

template <class T>
void integrate(int mp_id, 
               int t_span, 
               int step ,
               void(T::*callback)(const coord_type, double) = (Integrator::*)(const coord_type, double))
{
    //calls callback here
}

it looks like you are trying to declaring a method that takes a callback function as a parameter and assigning a default value.看起来您正在尝试声明一个将回调函数作为参数并分配默认值的方法。 Unfortunately the default value looks like the declaration of another method pointer and not a method.不幸的是,默认值看起来像是另一个方法指针的声明,而不是一个方法。 You need to use a pointer to a method of T .您需要使用指向T方法的指针。

template <class T>
void integrate(int mp_id, 
               int t_span, 
               int step ,
               void(T::*callback)(const coord_type, double) = &Integrator::base_integrate_callback)
{
    //calls callback here
}

but I don't think this will be kosher as there is no way to ensure that T and Integrator are in any way related.但我不认为这会是 kosher 的,因为没有办法确保TIntegrator有任何关联。

For example, after cleaning up例如,清理后

integrator_1.integrate < caller > (mp_id, span, step, &A.callback);

to

integrator_1.integrate < caller > (mp_id, span, step, &caller::callback);

because you need to provide a pointer to a method, not an object referring to a method.因为您需要提供指向方法的指针,而不是引用方法的对象。 This exposes another problem we'll get to in a moment, but it will compile for now and let us continue.这暴露了我们稍后会遇到的另一个问题,但它现在会编译并让我们继续。

But this would not但这不会

integrator_1.integrate < caller > (mp_id, span, step);

because the signature of Integrator::base_integrate_callback , void Integrator::base_integrate_callback(const coord_type, double), does not match the signature of void(caller::*callback)(const coord_type, double) .因为Integrator::base_integrate_callback的签名 void Integrator::base_integrate_callback(const coord_type, double) 与void(caller::*callback)(const coord_type, double)的签名不匹配。 They look the same, don't they?他们看起来一样,不是吗? What's missing is the hidden this parameter all methods have.缺少的是所有方法都隐藏的this参数。 caller::*callback expects a caller * , but Integrator::base_integrate_callback provides Integrator * . caller::*callback需要caller * ,但Integrator::base_integrate_callback提供Integrator *

You can fix this by making caller and it's ilk inherit Integrator rather than MyIntegrator , but moving base_integrate_callback to a new struct Integrated and having caller and friends inherit Integrated would make more sense.您可以通过使caller和它的同类继承Integrator而不是MyIntegrator来解决此MyIntegrator ,但是将base_integrate_callback移动到新的struct Integrated并让caller和朋友继承Integrated会更有意义。

And back to the other problem I mentioned earlier.回到我之前提到的另一个问题。 In

template <class T>
void integrate(int mp_id, 
               int t_span, 
               int step ,
               void(T::*callback)(const coord_type, double) = &Integrated::base_integrate_callback)
{
    coord_type x; // junk for example
    double y; //junk for example
    callback(x,y); //KABOOM!
}

On what object is callback being invoked?在哪个对象上调用回调? integrate will need one more parameter, a reference to T to provide context for callback . integrate将需要一个更多的参数,一个对T的引用来为callback提供上下文。

template <class T>
void integrate(int mp_id, 
               int t_span, 
               int step,
               T & integrated,
               void(T::*callback)(const coord_type, double) = &Integrated::base_integrate_callback)
{
    coord_type x; // junk for example
    double y; //junk for example
    integrated.callback(x,y);
}

Then you have to use the correct syntax to invoke the function pointer because the above will always call caller::callback .然后你必须使用正确的语法来调用函数指针,因为上面总是会调用caller::callback

template <class T>
void integrate(int mp_id, 
               int t_span, 
               int step,
               T & integrated,
               void(T::*callback)(const coord_type, double) = &Integrated::base_integrate_callback)
{
    coord_type x; // junk for example
    double y; //junk for example
    (integrated.*callback)(x,y); //std::invoke would be preferred if available
}

All together:全部一起:

#include <array>
#include <iostream>

class Integrator
{
public:
    using coord_type = std::array<double, 3>;
};

struct Integrated
{
    void base_integrate_callback(const Integrator::coord_type, double t_k)
    {
        std::cout << "made it to default" << std::endl;
    }
};

class MyIntegrator: public Integrator
{
public:
    template <class T>
    void integrate(int mp_id,
                   int t_span,
                   int step,
                   T & integrated,
            void(T::*callback)(const coord_type, double) = &Integrated::base_integrate_callback)
    {
        coord_type x; // junk for example
        double y = 0; //junk for example
        (integrated.*callback)(x,y);
    }
};


struct caller:public Integrated
{
    char val; // for test purposes
    caller(char inval): val(inval) // for test purposes
    {

    }
    void callback(const Integrator::coord_type coord, double t_k)
    {
        std::cout << "made it to " << val << std::endl;
    }
};

int main()
{
    MyIntegrator integrator_1;
    caller A {'A'};
    caller B {'B'};
    caller C {'C'};
    int mp_id = 1;
    int span = 365;
    int step = 1;
    integrator_1.integrate < caller > (mp_id, span, step, A, &caller::callback);
    integrator_1.integrate < caller > (mp_id, span, step, B, &caller::callback);
    integrator_1.integrate < caller > (mp_id, span, step, C);
    return 0;
}

Recommendation: Step into 2011 and see what std::function and lambda expressions can do for for you.建议:进入 2011 年,看看std::functionlambda 表达式可以为您做什么。

Here's an example:下面是一个例子:

#include <array>
#include <iostream>
#include <functional>

class Integrator
{
public:
    using coord_type = std::array<double, 3>;
};

// no need for integrated to get default callback

class MyIntegrator: public Integrator
{
public:
    template <class T>
    void integrate(int mp_id,
                   int t_span,
                   int step,
                   // no need to provide object instance for callback. packed with std::bind
                   std::function<void(const coord_type, double)> callback =
                           [](const coord_type, double) { std::cout << "made it to default" << std::endl; })
                           // default callback is now lambda expression
    {
        coord_type x; // junk for example
        double y = 0; //junk for example
        callback(x,y); // no weird syntax. Just call a function
    }
};


struct caller
{
    char val; // for test purposes
    // no need for test constructor
    void callback(const Integrator::coord_type coord, double t_k)
    {
        std::cout << "made it to " << val << std::endl;
    }
};

int main()
{
    MyIntegrator integrator_1;
    caller A {'A'};
    caller B {'B'};
    // no need for test object C
    int mp_id = 1;
    int span = 365;
    int step = 1;
    using namespace std::placeholders; // shorten placeholder names
    integrator_1.integrate < caller > (mp_id, 
                                       span, 
                                       step, 
                                       std::bind(&caller::callback, A, _1, _2));
    // std bind bundles the object and the callback together into one callable package

    integrator_1.integrate < caller > (mp_id, 
                                       span, 
                                       step, 
                                       [B](const Integrator::coord_type p1, 
                                           double p2) mutable // lambda captures default to const 
                                       { 
                                           B.callback(p1, p2); // and callback is not a const method
                                       });
    // Using lambda in place of std::bind. Bit bulkier, but often swifter and no 
    //need for placeholders

    integrator_1.integrate < caller > (mp_id,
                                       span,
                                       step,
                                       [](const Integrator::coord_type p1,
                                           double p2)
                                       {
                                           std::cout << "Raw Lambda. No callback object at all." << std::endl;
                                       });
    //custom callback without a callback object

    integrator_1.integrate < caller > (mp_id, span, step);
    //call default

    return 0;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM