传递指向 multiply 类 的指针给成员函数
passing pointer to multiply classes to a member function
我有下一个 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;
}
尝试编译时出现错误:
file:integration.h, line 18, syntax error: '< tag>::*'
如何调用属于任何 class 的回调?
第二个问题:当我尝试在没有显式模板规范的情况下调用它时,例如
integrator_1.integrate(mp_id,span,step,&A.callback);
我收到一个错误
file: main.cpp , line 65, 'MyIntegrator::integrate': no matching overloaded function found
那么,为什么这个函数不能从它的参数推导出它的参数?
我在没有依赖默认参数的最后一个参数调用它时也得到同样的错误。
integrator_1.integrate(mp_id,span,step);
用一点缩进解密你在这里的内容
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
}
您似乎正在尝试声明一个将回调函数作为参数并分配默认值的方法。不幸的是,默认值看起来像是另一个方法指针而不是方法的声明。您需要使用指向 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
}
但我认为这不会是犹太洁食,因为无法确保 T
和 Integrator
有任何关联。
例如清理后
integrator_1.integrate < caller > (mp_id, span, step, &A.callback);
到
integrator_1.integrate < caller > (mp_id, span, step, &caller::callback);
因为您需要提供指向方法的指针,而不是引用方法的对象。这暴露了我们稍后会遇到的另一个问题,但它现在会编译并让我们继续。
但这不会
integrator_1.integrate < caller > (mp_id, span, step);
因为Integrator::base_integrate_callback
的签名,void Integrator::base_integrate_callback(const coord_type,double),与void(caller::*callback)(const coord_type, double)
的签名不匹配。他们看起来一样,不是吗?缺少的是隐藏的 this
参数,所有方法都有。 caller::*callback
期望 caller *
,但 Integrator::base_integrate_callback
提供 Integrator *
。
您可以通过使 caller
继承 Integrator
而不是 MyIntegrator
来解决此问题,但将 base_integrate_callback
移动到新的 struct Integrated
并具有caller
和朋友继承 Integrated
会更有意义。
回到我之前提到的另一个问题。在
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!
}
在什么对象上调用回调? 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);
}
然后你必须使用正确的语法来调用函数指针,因为上面总是调用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
}
总计:
#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;
}
建议:步入 2011 年,看看 std::function
and lambda expressions 能为您做些什么。
这是一个例子:
#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;
}
我有下一个 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;
}
尝试编译时出现错误:
file:integration.h, line 18, syntax error: '< tag>::*'
如何调用属于任何 class 的回调?
第二个问题:当我尝试在没有显式模板规范的情况下调用它时,例如
integrator_1.integrate(mp_id,span,step,&A.callback);
我收到一个错误
file: main.cpp , line 65, 'MyIntegrator::integrate': no matching overloaded function found
那么,为什么这个函数不能从它的参数推导出它的参数?
我在没有依赖默认参数的最后一个参数调用它时也得到同样的错误。
integrator_1.integrate(mp_id,span,step);
用一点缩进解密你在这里的内容
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
}
您似乎正在尝试声明一个将回调函数作为参数并分配默认值的方法。不幸的是,默认值看起来像是另一个方法指针而不是方法的声明。您需要使用指向 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
}
但我认为这不会是犹太洁食,因为无法确保 T
和 Integrator
有任何关联。
例如清理后
integrator_1.integrate < caller > (mp_id, span, step, &A.callback);
到
integrator_1.integrate < caller > (mp_id, span, step, &caller::callback);
因为您需要提供指向方法的指针,而不是引用方法的对象。这暴露了我们稍后会遇到的另一个问题,但它现在会编译并让我们继续。
但这不会
integrator_1.integrate < caller > (mp_id, span, step);
因为Integrator::base_integrate_callback
的签名,void Integrator::base_integrate_callback(const coord_type,double),与void(caller::*callback)(const coord_type, double)
的签名不匹配。他们看起来一样,不是吗?缺少的是隐藏的 this
参数,所有方法都有。 caller::*callback
期望 caller *
,但 Integrator::base_integrate_callback
提供 Integrator *
。
您可以通过使 caller
继承 Integrator
而不是 MyIntegrator
来解决此问题,但将 base_integrate_callback
移动到新的 struct Integrated
并具有caller
和朋友继承 Integrated
会更有意义。
回到我之前提到的另一个问题。在
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!
}
在什么对象上调用回调? 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);
}
然后你必须使用正确的语法来调用函数指针,因为上面总是调用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
}
总计:
#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;
}
建议:步入 2011 年,看看 std::function
and lambda expressions 能为您做些什么。
这是一个例子:
#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;
}