C++ C++&引用;简单的;具有任意参数和返回值的函数的函数回调
我正在尝试创建一个简单的函数计时器/分析器。我的主要目标是创建一个函数,我可以快速、轻松、不引人注目地添加到任何我想要分析的函数调用中 例如,为了分析C++ C++&引用;简单的;具有任意参数和返回值的函数的函数回调,c++,callback,compiler-errors,profiling,function-pointers,C++,Callback,Compiler Errors,Profiling,Function Pointers,我正在尝试创建一个简单的函数计时器/分析器。我的主要目标是创建一个函数,我可以快速、轻松、不引人注目地添加到任何我想要分析的函数调用中 例如,为了分析foo、bar和baz,我想要一个ft(函数计时器)函数,它可以执行以下操作,对原始代码的影响尽可能小: ft(foo()); ft(bar(1, 2, 3)); int result = ft(baz()); string result = ft(qux("a", 2, 3.4)); 注意,对于baz和qux,从ft返回的结果应该是函数本身返回
foo
、bar
和baz
,我想要一个ft
(函数计时器)函数,它可以执行以下操作,对原始代码的影响尽可能小:
ft(foo());
ft(bar(1, 2, 3));
int result = ft(baz());
string result = ft(qux("a", 2, 3.4));
注意,对于baz
和qux
,从ft
返回的结果应该是函数本身返回的结果
ft
处理所有计时和记录等
我遇到过几个线程,它们提到了如何对具有任意参数的函数执行函数回调,但没有太多线程提到如何处理返回值
这是最接近的:但我在尝试处理void函数以及返回值的函数时陷入了困境
我开始认为使用宏是实现这一点的方法,但也许有更好的方法
以下是我目前的微弱尝试(节略):
静态定时器fTimer;
类库
{
公众:
虚空运算符()()=0;
};
类VoidFuncWrapper0:公共VoidFuncBase
{
公众:
typedef void(*func)();
VoidFuncWrapper0(func-fp):fp((fp){}
void运算符()
私人:
func fp_2;;
};
模板
类VoidFuncWrapper1:公共VoidFuncBase
{
公众:
类型定义无效(*func)(常量P1&);
VoidFuncWrapper1(func fp,const P1&P1):fp_(fp),P1_(P1){}
void运算符()
私人:
func fp_2;;
P1;
};
模板
类VoidFuncWrapper2:公共VoidFuncBase
{
公众:
typedef void(*func)(常数P1和,常数P2和);
VoidFuncWrapper2(函数fp、常数P1和P1、常数P2和P2)
:fp_(fp),p1_(p1),p2_(p2){}
void运算符()
私人:
func fp_2;;
P1;
P2;
};
模板
类函数基
{
公众:
虚拟R运算符()()=0;
};
模板
类FuncWrapper0:公共FuncBase
{
公众:
typedef R(*func)();
FuncWrapper0(func-fp):fp_2;(fp){}
R运算符()({return fp_();}
私人:
func fp_2;;
};
模板
类FuncWrapper1:公共FuncBase
{
公众:
类型定义R(*func)(常数P1&);
FuncWrapper1(func fp,const P1&P1):fp_(fp),P1_(P1){}
R运算符(){return fp_u1;(p1_1;);}
私人:
func fp_2;;
P1;
};
模板
类FuncWrapper2:公共FuncBase
{
公众:
类型定义R(*函数)(常数P1和,常数P2和);
FuncWrapper2(函数fp、常数P1和P1、常数P2和P2)
:fp_(fp),p1_(p1),p2_(p2){}
R运算符(){return fp_u1;(p1_1;,p2_1;)}
私人:
func fp_2;;
P1;
P2;
};
模板
R ft(FuncBase func,std::string functionName)
{
无符号长线程ID=getThreadId();
double starttimes=fTimer.getmillizes();
R结果=func();
double duration=fTimer.getmillizes()-starttimes;
logf(“%u%s采取了%fms”,线程ID,functionName.c_str(),持续时间);
返回结果;
}
void ft(VoidFuncBase func,std::string functionName,int logTimeoutMs)
{
无符号长线程ID=getThreadId();
double starttimes=timer.getmillizes();
func();
double duration=timer.getmillizes()-starttimes;
logf(“%u%s采取了%fms”,线程ID,functionName.c_str(),持续时间);
}
目前我正在
错误:无法将参数“func”声明为抽象类型
“VoidFuncBase”
但无论如何,我可能朝着错误的方向前进。可变模板是正确的选择!在任何情况下,您都需要稍微更改函数的调用方式:
template <typename R, typename... T, typename... A>
R ft(R (*f)(T...), A&&... a) {
// do you business
return f(std::forward<A>(a)...);
}
int r0 = ft(&baz);
int r1 = ft(&qax, a, b, c);
模板
R英尺(R(*f)(T…)、A和A){
//你有生意吗
返回f(标准:正向(a)…);
}
int r0=英尺(&baz);
int r1=英尺(&qax,a,b,c);
不过,当函数重载时,事情就变得有趣了。请注意,调用后的任何处理只会进入调用前设置的对象的析构函数。Deitmar的回答是解决方案的95%,但以下是我为使其在我的情况下工作所做的调整:
ft
返回之前做一些工作,因此对代码进行了一些简单的修改Shape* shape = getShape();
double area = 0.0;
if(shape->getType() == SQUARE)
{
area = ft((Square*)shape, &Square::getArea, "Square::getArea");
}
else if(shape->getType() == TRIANGLE)
{
area = ft((Triangle*)shape, &Triangle::getArea, "Triangle::getArea");
}
else if(shape->getType() == CIRCLE)
{
area = ft((Circle*)shape, &Circle::getArea, "Circle::getArea");
}
在c++11中有一个很好的std::函数。在c++03中,这是一件非常麻烦的事情,因为您必须创建各种模板类和functions@VJovic:所有类型,如非类型模板参数、表达式模板、类型特征、奇怪的重复模板模式等。。。,没有语言叫做C/C++,我知道没有语言叫做C/C++,但是我用它来表示我将对C或C++的实现都有价值。您需要能够读取调用堆栈,并在中断时执行。如果采集了100个样本,其中40%的样本出现了一条线,那么如果您可以消除该线,则总时间将减少40%。(这是一个1.67或67%的加速比)所以它不仅找到了昂贵的函数,还找到了昂贵的线路。它不需要非常精确或高效。它无论如何都会找到它们,递归也会找到
template <class C, typename R, typename... T, typename... A>
R ft(C* obj, R (C::*func)(T...), std::string functionName, A&&... args)
{
double startTimeMs = fTimer.getMilliseconds();
//extra pre-call work
R result = (obj->*func)(std::forward<A>(args)...);
//extra post-call work
double duration = fTimer.getMilliseconds() - startTimeMs;
logf("%s took %fms", functionName.c_str(), duration);
return result;
}
template <class C, typename... T, typename... A>
void ft(C* obj, void (C::*func)(T...), std::string functionName, A&&... args)
{
double startTimeMs = fTimer.getMilliseconds();
//extra pre-call work
(obj->*func)(std::forward<A>(args)...);
//extra post-call work
double duration = fTimer.getMilliseconds() - startTimeMs;
logf("%s took %fms", functionName.c_str(), duration);
}
ft(this, &Foo::bar, "Foo::bar", (3));
Shape* shape = getShape();
double area = 0.0;
if(shape->getType() == SQUARE)
{
area = ft((Square*)shape, &Square::getArea, "Square::getArea");
}
else if(shape->getType() == TRIANGLE)
{
area = ft((Triangle*)shape, &Triangle::getArea, "Triangle::getArea");
}
else if(shape->getType() == CIRCLE)
{
area = ft((Circle*)shape, &Circle::getArea, "Circle::getArea");
}