能否实现以函数为参数的重复执行计时函数?
你的计时函数需求完全可行!
当然没问题!这种封装重复计时逻辑的需求在C++里非常常见,刚好能帮你把重复的代码抽出来,让各个作业环节的计时代码更简洁。下面给你详细的实现思路和代码示例:
核心实现思路
1. 支持两种调用方式
用函数重载或者默认参数就能实现timingRoutine(functionName)和timingRoutine(repetitions, functionName)两种调用形式。推荐用重载,配合模板来兼容不同参数的目标函数。
2. 兼容带参数的目标函数
你的countLastName有三个参数,直接传函数指针没法带参数,所以需要用模板+完美转发来处理任意参数的函数,或者用std::bind绑定参数后再传入。
3. 复用你已有的计时逻辑
你原来用clock()统计CPU时间的思路是对的,它比墙钟时间(比如std::chrono::system_clock)更适合计算函数执行的实际耗时,因为它只统计程序占用的CPU资源,不受其他进程影响。
完整代码示例
#include <iostream> #include <ctime> #include <functional> #include <string> // 假设你的Person结构体定义 struct Person { std::string firstName; std::string lastName; }; // 模板版本:支持指定重复次数,兼容任意参数的可调用对象 template<typename Func, typename... Args> double timingRoutine(int repetitions, Func func, Args&&... args) { // 可选:先调用一次排除缓存预热的影响 std::invoke(func, std::forward<Args>(args)...); clock_t startTime = clock(); for(int i = 0; i < repetitions; ++i) { std::invoke(func, std::forward<Args>(args)...); } clock_t endTime = clock(); // 计算单次平均耗时 return static_cast<double>(endTime - startTime) / CLOCKS_PER_SEC / repetitions; } // 重载版本:使用默认重复次数(和你原来的100000一致) template<typename Func, typename... Args> double timingRoutine(Func func, Args&&... args) { const int DEFAULT_REPS = 100000; return timingRoutine(DEFAULT_REPS, func, std::forward<Args>(args)...); } // 你的countLastName函数 int countLastName(const std::string& lastName, const Person* peopleArray, size_t size) { int count = 0; for(size_t i = 0; i < size; ++i) { if(peopleArray[i].lastName == lastName) { ++count; } } return count; } // 使用示例 int main() { Person people[] = {{"Alice", "Smith"}, {"Bob", "Smith"}, {"Charlie", "Brown"}}; size_t arrSize = sizeof(people) / sizeof(people[0]); // 调用方式1:用默认重复次数 double avgTime1 = timingRoutine(countLastName, "Smith", people, arrSize); std::cout << "默认10万次重复,单次平均耗时:" << avgTime1 * 1e6 << " 微秒\n"; // 调用方式2:指定重复次数 double avgTime2 = timingRoutine(500000, countLastName, "Smith", people, arrSize); std::cout << "50万次重复,单次平均耗时:" << avgTime2 * 1e6 << " 微秒\n"; return 0; }
关键细节说明
std::invoke:兼容普通函数、lambda表达式、成员函数等各种可调用对象,比直接调用更灵活。- 完美转发
std::forward<Args>(args)...:保证参数传递时的效率,避免不必要的拷贝(比如你的std::string参数)。 - 缓存预热:代码里注释的那行提前调用函数,是为了避免第一次执行时的缓存加载开销影响计时结果,如果你不需要可以删掉。
额外优化建议
- 自动调整重复次数:如果你的函数执行极快,固定重复次数可能导致计时误差大。可以改成循环直到总耗时超过0.1秒,再计算平均耗时,这样结果更准确。
- 输出格式化:把耗时转换成微秒(乘以1e6)或者纳秒,比直接输出秒数更直观,因为单次函数耗时通常很小。
- 封装成类(可选):如果作业里需要更复杂的计时(比如多次测试取中位数),可以把计时逻辑封装成一个类,方便扩展。
内容的提问来源于stack exchange,提问作者JohnBoyTheGreat
相关产品推荐
相关产品推荐

