引入
- 本文实现的是一个计算用户函数执行时间的函数编写,实现功能如下
- 用户将待测量时间的函数传入此函数,此函数自行调用传入的用户函数并输出用户函数的执行时间
- 自推导用户函数的返回类型,可以
直接替代原本用户函数的位置
,实现一种类似函数包装器
的功能,返回和直接调用用户函数相同类型相同结果的输出
主体一览
- 老规矩先上代码主体后面再详细说明(见文章底部)
// 用于处理返回类型为 void 的函数 template <typename F, typename... Args, typename = typename std::enable_if<std::is_void<typename std::result_of<F(Args...)>::type>::value>::type> void measureTime(F func, Args&&... args) { auto beforeTime = std::chrono::steady_clock::now(); func(std::forward<Args>(args)...); auto afterTime = std::chrono::steady_clock::now(); double duration_millisecond = std::chrono::duration<double, std::milli>(afterTime - beforeTime).count(); std::cout << "Function execution took " << duration_millisecond << " ms." << std::endl; } // 用于处理非 void 返回类型的函数 template <typename F, typename... Args, typename = typename std::enable_if<!std::is_void<typename std::result_of<F(Args...)>::type>::value>::type, typename ReturnType = typename std::result_of<F(Args...)>::type> ReturnType measureTime(F func, Args&&... args) { auto beforeTime = std::chrono::steady_clock::now(); auto result = func(std::forward<Args>(args)...); auto afterTime = std::chrono::steady_clock::now(); double duration_millisecond = std::chrono::duration<double, std::milli>(afterTime - beforeTime).count(); std::cout << "Function execution took " << duration_millisecond << " ms." << std::endl; return result; }
使用说明
- 需要包含的头文件
#include <iostream>
#include <chrono>
#include <functional>
#include <type_traits>
-
计算普通函数运行时间
void fun() { for (int i = 0; i <10000000;i++) { static int j=0;//模拟耗时操作 j*=1.5; } } double add(const double&a, const double& b) { return a + b; } int main() { measureTime(fun); double result = measureTime(std::bind(add, 10.0, 20.0));//使用std::bind进行绑定参数 std::cout<<"result:"<<result<<std::endl; return 0; }
- 输出结果
- 输出结果
-
类内计算类内成员函数
class MyClass { public: void print() { for (int i = 0; i <1000000;i++) { static int j=0; j++; } std::cout<<"print"<<std::endl; } double add(double a, double b){ for (int i = 0; i <10000000;i++) { static int j=0; j++; } return a+b; } void dosomething(); }; void MyClass::dosomething() { measureTime(std::bind(&MyClass::print, this)); double result = measureTime(std::bind(&MyClass::add, this, std::placeholders::_1, std::placeholders::_2), 10, 10); std::cout << "result" <<result << std::endl; } int main() { MyClass myclass; myclass.dosomething(); return 0; }
- 输出结果
- 输出结果
代码详解
- 我们先来讲解用户函数返回类型为void的情况
- 首先我们看第一行模板声明
template <typename F, typename... Args,typename = typename std::enable_if<std::is_void<typename std::result_of<F(Args...)>::type>::value>::type>
typename F
是函数模板类型typename... Args
是函数参数的包扩展,变长参数,类似于python的**kwargs
传递不确定数量的关键字参数std::enable_if
用于条件化地启用模板std::is_void
判断类型是否为空F(Args...)>::type
这个为函数的返回类型- 上面三条连起来就是
std::enable_if<std::is_void<typename std::result_of<F(Args...)>::type>::value>::type>
当函数返回类型为空的时候执行此模板,也就是这个版本的函数重载
- 函数声明
void measureTime(F func, Args&&... args);
- 这行就没什么了,传入用户函数,接受变长参数模板
- 注意这里
Args&&... args
的&&
表示剩余的参数是通过右值引用传递的,允许完美转发。(C++11的右值引用,移动特性)
- 调用返回类型为void的用户函数
func(std::forward<Args>(args)...);:
std::forward<Args>(args)...
调用传入的函数 func,并使用std::forward
进行完美转发参数,保证参数保持其左值或右值属性。(配合上面的&&
移动)
- 用户函数执行时间计算
- 这边就不过多讲解了,都是
chrono
库的常用操作
auto beforeTime = std::chrono::steady_clock::now(); // 记录开始时间 //-- auto afterTime = std::chrono::steady_clock::now(); // 记录结束时间 double duration_millisecond = std::chrono::duration<double, std::milli>(afterTime - beforeTime).count(); std::cout << "Function execution took " << duration_millisecond << " ms." << std::endl;
- 这边就不过多讲解了,都是
- 然后来讲讲返回类型不为void类型的函数
template <typename F, typename... Args, typename = typename std::enable_if<!std::is_void<typename std::result_of<F(Args...)>::type>::value>::type, typename ReturnType = typename std::result_of<F(Args...)>::type>
- 其实这里和上面那个模板基本上一个意思
!std::is_void<typename std::result_of<F(Args...)>::type
这里判断不为void类型typename ReturnType = typename std::result_of<F(Args...)>::type>
这里拿到用户的返回类型- 其他的内容和前面是一样的,这里不多说明了
结语
- 每天一点C++,越学越不会,预祝大家也越学越好!在编程路上越来越远~