如何在C++中复用基准测试函数处理不同类型的单/双参数学函数
解决方案
单参测试函数:用模板替代重载
直接把你现有的单参float测试函数改成模板函数,靠C++模板的类型推导自动适配float和double类型,完全复用函数逻辑,不用复制粘贴或写重载:
#include <chrono> #include <cmath> #include <vector> #include <type_traits> template<typename T> void timeit_single_arg(T(*func)(T), const std::vector<T>& test_inputs, const std::string& func_name) { // 计时逻辑 auto start = std::chrono::high_resolution_clock::now(); for (T input : test_inputs) { // 用volatile防止编译器优化掉函数调用 volatile T result = func(input); } auto end = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start); std::cout << func_name << " 执行时间: " << duration.count() << " us\n"; // 精度测试逻辑 double max_error = 0.0; for (T input : test_inputs) { T custom_result = func(input); // 根据T的类型调用对应的库函数 T lib_result = std::is_same_v<T, float> ? std::expf(input) : std::exp(input); double error = std::abs(static_cast<double>(custom_result - lib_result)) / std::abs(static_cast<double>(lib_result)); if (error > max_error) max_error = error; } std::cout << func_name << " 最大相对误差: " << max_error << "\n"; }
调用时直接传对应类型的自定义函数即可,模板会自动推导T:
// 测试float版自定义exp timeit_single_arg(&custom_exp_float, float_test_inputs, "custom_exp_float"); // 测试double版自定义exp timeit_single_arg(&custom_exp_double, double_test_inputs, "custom_exp_double");
双参测试函数:模板适配多类型第二个参数
双参函数的第二个参数类型不影响测试逻辑,同样用模板处理第二个参数的类型,实现一次编写适配所有合法参数组合:
template<typename T, typename Arg2> void timeit_double_arg(T(*func)(T, Arg2), const std::vector<T>& test_inputs, const std::vector<Arg2>& arg2_inputs, const std::string& func_name) { // 计时逻辑 auto start = std::chrono::high_resolution_clock::now(); for (size_t i = 0; i < test_inputs.size(); ++i) { volatile T result = func(test_inputs[i], arg2_inputs[i]); } auto end = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start); std::cout << func_name << " 执行时间: " << duration.count() << " us\n"; // 精度测试逻辑 double max_error = 0.0; for (size_t i = 0; i < test_inputs.size(); ++i) { T custom_result = func(test_inputs[i], arg2_inputs[i]); T lib_result; // 编译期判断类型,调用对应库函数 if constexpr (std::is_same_v<T, float>) { if constexpr (std::is_same_v<Arg2, int>) { lib_result = std::powf(test_inputs[i], arg2_inputs[i]); } else { lib_result = std::powf(test_inputs[i], static_cast<float>(arg2_inputs[i])); } } else { if constexpr (std::is_same_v<Arg2, int>) { lib_result = std::pow(test_inputs[i], arg2_inputs[i]); } else { lib_result = std::pow(test_inputs[i], static_cast<double>(arg2_inputs[i])); } } double error = std::abs(static_cast<double>(custom_result - lib_result)) / std::abs(static_cast<double>(lib_result)); if (error > max_error) max_error = error; } std::cout << func_name << " 最大相对误差: " << max_error << "\n"; }
调用时自动适配第二个参数的int/float/double类型:
// 测试double+int版自定义pow timeit_double_arg(&custom_pow_double_int, double_inputs, int_args, "custom_pow_double_int"); // 测试float+float版自定义pow timeit_double_arg(&custom_pow_float_float, float_inputs, float_args, "custom_pow_float_float");
关于std::variant的替代说明
你之前尝试用std::variant处理多类型输入完全没必要,模板的类型推导已经能完美解决类型适配问题,还避免了variant需要手动判断类型、值比较繁琐的问题。如果一定要用variant存储测试数据,可以结合std::visit来分发处理,但模板方案在你的测试场景下更简洁高效。
内容的提问来源于stack exchange,提问作者Ξένη Γήινος
相关产品推荐
相关产品推荐

