基于C++11函数模板实现自动推导返回类型的函数执行时间测量

引入

  • 本文实现的是一个计算用户函数执行时间的函数编写,实现功能如下
    • 用户将待测量时间的函数传入此函数,此函数自行调用传入的用户函数并输出用户函数的执行时间
    • 自推导用户函数的返回类型,可以直接替代原本用户函数的位置,实现一种类似函数包装器的功能,返回和直接调用用户函数相同类型相同结果的输出

主体一览

  • 老规矩先上代码主体后面再详细说明(见文章底部)
    // 用于处理返回类型为 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++,越学越不会,预祝大家也越学越好!在编程路上越来越远~
  • 30
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值