我正在尝试创建一个简单的函数计时器/分析器。我的主要目标是创建一个可以快速、轻松且不显眼地添加到我想要分析的任何函数调用中的函数。
例如,要分析foo
、bar
和baz
我想要一个ft
(函数timer) 函数,可以做以下事情,尽可能少的影响原来的代码:
ft(foo());
ft(bar(1, 2, 3));
int result = ft(baz());
string result = ft(qux("a", 2, 3.4));
请注意,对于 baz
和 qux
,从 ft
返回的结果应该是函数本身返回的结果。
ft
处理所有的计时和日志记录等。
我遇到过几个线程,它们提到如何为具有任意参数的函数执行函数回调,但甚至没有提到如何处理返回值。
这是最接近的:Variable number of arguments (va_list) with a function callback?但是在尝试处理 void 函数以及返回值的函数时,我陷入了困境。
我开始认为使用宏是执行此操作的方法,但也许有更好的方法。
这是我目前的微弱尝试(删节):
static Timer fTimer;
class VoidFuncBase
{
public:
virtual void operator()() = 0;
};
class VoidFuncWrapper0 : public VoidFuncBase
{
public:
typedef void (*func)();
VoidFuncWrapper0(func fp) : fp_(fp) { }
void operator()() { fp_(); }
private:
func fp_;
};
template<typename P1>
class VoidFuncWrapper1 : public VoidFuncBase
{
public:
typedef void (*func)(const P1 &);
VoidFuncWrapper1(func fp, const P1 &p1) : fp_(fp), p1_(p1) { }
void operator()() { fp_(p1_); }
private:
func fp_;
P1 p1_;
};
template<typename P1, typename P2>
class VoidFuncWrapper2 : public VoidFuncBase
{
public:
typedef void (*func)(const P1 &, const P2 &);
VoidFuncWrapper2(func fp, const P1 &p1, const P2 &p2)
: fp_(fp), p1_(p1), p2_(p2) { }
void operator()() { fp_(p1_, p2_); }
private:
func fp_;
P1 p1_;
P2 p2_;
};
template<typename R>
class FuncBase
{
public:
virtual R operator()() = 0;
};
template<typename R>
class FuncWrapper0 : public FuncBase<R>
{
public:
typedef R (*func)();
FuncWrapper0(func fp) : fp_(fp) { }
R operator()() { return fp_(); }
private:
func fp_;
};
template<typename R, typename P1>
class FuncWrapper1 : public FuncBase<R>
{
public:
typedef R (*func)(const P1 &);
FuncWrapper1(func fp, const P1 &p1) : fp_(fp), p1_(p1) { }
R operator()() { return fp_(p1_); }
private:
func fp_;
P1 p1_;
};
template<typename R, typename P1, typename P2>
class FuncWrapper2 : public FuncBase<R>
{
public:
typedef R (*func)(const P1 &, const P2 &);
FuncWrapper2(func fp, const P1 &p1, const P2 &p2)
: fp_(fp), p1_(p1), p2_(p2) { }
R operator()() { return fp_(p1_, p2_); }
private:
func fp_;
P1 p1_;
P2 p2_;
};
template<typename R>
R ft(FuncBase<R> func, std::string functionName)
{
unsigned long threadId = getThreadId();
double startTimeMs = fTimer.getMilliseconds();
R result = func();
double duration = fTimer.getMilliseconds() - startTimeMs;
logf("%u %s took %fms", threadId, functionName.c_str(), duration);
return result;
}
void ft(VoidFuncBase func, std::string functionName, int logTimeoutMs)
{
unsigned long threadId = getThreadId();
double startTimeMs = timer.getMilliseconds();
func();
double duration = timer.getMilliseconds() - startTimeMs;
logf("%u %s took %fms", threadId, functionName.c_str(), duration);
}
目前我得到
"error: cannot declare parameter 'func' to be of abstract type '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);
不过,当函数重载时,事情会变得有趣。请注意,调用后的任何处理都会进入调用前设置的对象的析构函数。
关于C++ "simple"具有任意参数和返回值的函数的函数回调,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9634775/