前言
前面一篇文章利用了可变参宏去实现任意函数计时功能,总觉得有点挫,而且无法带返回值。突然想到可以用模板实现这个功能。下面讲一下实现思路和中间碰到的问题。
一、万能函数模板
先介绍一下万能函数模板,用下面两个函数模板,无论是全局函数,还是类成员函数,统统可以执行。原理就是万能函数指针加上可变参。省略号的位置自己体会一下。
template<typename R, typename... Args>
R CheckPerf(R(*ptr)(Args...), Args... args)
{
return ptr(args...);
}
template<typename R, typename T,typename... Args>
R CheckPerf(R(T::*ptr)(Args...), T* obj, Args... args)
{
auto func = std::bind(ptr,obj);
return func(args...);
}
二、void返回值问题
我要把函数放在中间计时,然后最后返回结果。自然而然的是想到分两种情况,因为void是无法定义中间变量的,于是我就写了下面的代码。但总感觉有点憨憨。
//返回值为void,
//当然可以去掉一些东西,typename std::enable_if这可以完全不要,直接特化
//但为了学习嘛
template<typename R, typename... Args>
typename std::enable_if<std::is_same<R, void>::value == true, R>::type
CheckPerf(char* funcname, R(*ptr)(Args...), Args... args)
{
auto t1 = chrono::system_clock::now();
ptr(args...);
auto t2 = chrono::system_clock::now();
auto time = chrono::duration_cast<chrono::milliseconds>(t2 - t1).count();
printf("[%s] pass time:%lld ms\n", funcname, time);
}
//返回值不为void
template<typename R, typename... Args>
typename std::enable_if<std::is_same<R, void>::value == false, R>::type
CheckPerf(char* funcname, R(*ptr)(Args...), Args... args)
{
auto t1 = chrono::system_clock::now();
R result = ptr(args...);
auto t2 = chrono::system_clock::now();
auto time = chrono::duration_cast<chrono::milliseconds>(t2 - t1).count();
printf("[%s] pass time:%lld ms\n", funcname, time);
return result;
}
三、利用局部变量计时,解决void返回值接收问题
我们可以在局部变量的构造函数中记录开始时刻,析构函数中记录结束时刻,这样就可以直接return 函数,不用接收中间结果。
#include <functional>
#include <chrono>
class Time_span{
public:
Time_span(char* funcname,int& time):time(time)
{
t1 = chrono::system_clock::now();
this->funcname = funcname;
}
~Time_span()
{
auto t2 = chrono::system_clock::now();
time = chrono::duration_cast<chrono::milliseconds>(t2 - t1).count();
printf("[%s] pass time:%d ms\n", funcname.c_str(), time);
}
private:
std::chrono::system_clock::time_point t1;
std::string funcname;
int& time;
};
template<typename R, typename... Args>
R CheckPerf(char* funcname, int& time, R(*ptr)(Args...), Args... args)
{
Time_span span(funcname,time);
return ptr(args...);
}
完全版代码
class Time_span{
public:
Time_span(char* funcname,int& time):time(time)
{
t1 = chrono::system_clock::now();
this->funcname = funcname;
}
~Time_span()
{
auto t2 = chrono::system_clock::now();
time = chrono::duration_cast<chrono::milliseconds>(t2 - t1).count();
printf("[%s] pass time:%d ms\n", funcname.c_str(), time);
}
private:
std::chrono::system_clock::time_point t1;
std::string funcname;
int& time;
};
template<typename R, typename... Args>
R CheckPerf(char* funcname, int& time, R(*ptr)(Args...), Args... args)
{
Time_span span(funcname,time);
return ptr(args...);
}
template<typename R, typename T,typename... Args>
R CheckPerf(char* funcname,int& time R(T::*ptr)(Args...), T* obj, Args... args)
{
Time_span span(funcname,time);
auto func = std::bind(ptr,obj);
return func(args...);
}
class Test
{
public:
void print() {
}
};
int TestFunc(int a,int b){
return 1;}
#define check_perf_time_return(func,t,...) CheckPerf(#func,t,func, ##__VA_ARGS__)
int main()
{
Test test;
int time;
check_perf_time_return(&Test::print,time,&test);
check_perf_time_return(TestFunc,time,1,2);
}