c++ - 使用 C++14 lambda 测量任意函数的执行时间
问题描述
Scott Meyer 的书“Effective Modern C++”的第 24 项让我很兴奋。他提到了编写 C++14 lambda 来记录任意函数调用所用时间的可能性。
我仍处于学习 C++14 特性的早期阶段。我的尝试(Main.cpp)看起来像这样来测量成员函数调用的时间:
#include <chrono>
#include <iostream>
auto measure = [](auto&& function, auto&&... parameters) -> decltype(function)
{
const std::chrono::steady_clock::time_point startTimePoint =
std::chrono::steady_clock::now();
const auto returnValue = std::forward<decltype(function)>(function)(
std::forward<decltype(parameters)>(parameters)...);
const std::chrono::steady_clock::time_point stopTimePoint =
std::chrono::steady_clock::now();
const std::chrono::duration<double> timeSpan = std::chrono::duration_cast<
std::chrono::duration<double>>(stopTimePoint - startTimePoint);
std::cout << "Computation took " << timeSpan.count()
<< " seconds." << std::endl;
return returnValue;
};
class Test
{
public:
int computation(double dummy)
{
std::cout << "Received " << dummy << ". Computing..." << std::endl;
return 123;
}
};
int main(int, char**)
{
Test instance;
using Function = int (Test::*)(double);
Function function = instance.computation;
int result = measure(function, 1.0);
std::cout << "Result: " << result << std::endl;
return 0;
}
我收到以下编译错误:
..\src\Main.cpp: In function 'int main(int, char**)':
..\src\Main.cpp:43:36: error: cannot convert 'int (Test::*)(double)' to 'int' in initialization
int result = measure(function, 1.0);
^
..\src\Main.cpp: In instantiation of '<lambda(auto:1&&, auto:2&& ...)> [with auto:1 = int (Test::*&)(double); auto:2 = {double}; decltype (function) = int (Test::*&)(double)]':
..\src\Main.cpp:43:36: required from here
..\src\Main.cpp:9:69: error: must use '.*' or '->*' to call pointer-to-member function in 'std::forward<int (Test::*&)(double)>((* & function)) (...)', e.g. '(... ->* std::forward<int (Test::*&)(double)>((* & function))) (...)'
const auto returnValue = std::forward<decltype(function)>(function)(
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
std::forward<decltype(parameters)>(parameters)...);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
显然我做错了,但我不知道如何做对。有谁能够帮我?非常感谢!
解决方案
有两种方法可以处理此任务。
接受一个函数(或函数对象),返回一个修改后的函数,该函数与原始函数执行相同的操作,并测量时间。返回的对象类型不能与接受的参数类型相同。它必须是 lambda(或自定义类类型,但 lambda 更简单)。实际测量是在调用返回的对象时进行的。使用语法示例:
result = measure(foo)(param1, param2); // variant 1 auto measured_foo = measure(foo); result = measured_foo(param1, param2); // variant 2
接受函数(或函数对象)及其参数,调用它并执行测量。返回类型是原始函数的类型。使用语法示例:
result = measure(foo, param1, param2);
您measure
最接近第二个变体,唯一有问题的是声明。这是正确的:
auto measure = [](auto&& function, auto&&... parameters) -> decltype(auto)
准确地说,这不是唯一的错误。如果被测函数返回一个引用,则返回类型将是错误的。要解决此问题,请更换
const auto returnValue = ...
和
decltype(auto) returnValue = ...
在 lambda 体内
您的程序(但不是本身)的另一件事是measure
您尝试使用成员函数的方式。
Function function = instance.computation;
这只是行不通。使用 lambda 或std::bind
创建绑定的成员函数。关于在 stackoverflow 上正确的方法,有无数个问题(和很好的答案)。
现场演示(通过引用返回工作)。
如果您想要第一种创建测量函数的方法,方法如下:
auto measure = [](auto&& function) -> decltype(auto)
{
return [=](auto&&... parameters) mutable -> decltype(auto) {
const std::chrono::steady_clock::time_point startTimePoint =
std::chrono::steady_clock::now();
decltype(auto) result = function(std::forward<decltype(parameters)>(parameters)...);
const std::chrono::steady_clock::time_point stopTimePoint =
std::chrono::steady_clock::now();
const std::chrono::duration<double> timeSpan = std::chrono::duration_cast<
std::chrono::duration<double>>(stopTimePoint - startTimePoint);
std::cout << "Computation took " << timeSpan.count()
<< " seconds." << std::endl;
return result;
};
};
现场演示(通过引用返回)。
特别注意宗教用途decltype(auto)
。在mutable
第二个版本中也是如此。
推荐阅读
- amazon-web-services - “Mediainfo”权限被拒绝 AWS
- regex - 如何使用 sed 命令切换案例?
- python - numpy将值列添加到多维数组以进行区分
- php - 如何在 Laravel 中获取月度考勤报告
- php - 为 php 安装 sql server 驱动程序
- swift - 双转换错误 tvOS
- docker - 如何停止 VS2017 准备 docker 镜像
- angular - 将元素添加到 mat-tab-group 元素
- ruby-on-rails - 如何为关系传递序列化程序
- javascript - 使用 JavaScriptExecutor Selenium Java 更改 div 的样式高度