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%,但以下是我为使其在我的情况下工作所做的调整:

  • 为了支持void return类型的函数,我需要为这种情况添加一个特定的模板
  • 我需要调用方法而不是纯函数,因此我需要调整函数的引用方式
  • 可能是因为2,我发现我需要传入调用函数的对象。也许这实际上不是必要的,但这是我唯一能让它工作的方法
  • 我想在函数回调之后,但在
    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");
    }