I have been excited by item 24 of Scott Meyer's book "Effective Modern C++". He mentions the possibility to write a C++14 lambda to record the time taken in an arbitrary function invocation.
I am still in an early of learning C++14 features. My attempt (Main.cpp) looks like this for measuring the time of a member function call:
#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;
}
I get the following compilation errors:
..\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)...);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Obviously I am doing it wrong, but I could not figure out how to do it right. Can anybody help me? Thank you very much!
Have no clue what you are trying to do there but I am taking my guess here what I have done if this is what you are trying to do:
There are two ways to approach this task.
Accept a function (or a function object), return a modified function that does the same thing the original function does, plus measures the time. The returned object type cannot be the same as the accepted parameter type. It must be a lambda (or a custom class type, but the lambda is simpler). The actual measurement is performed when the returned object is invoked. Example usage syntax:
Accept a function (or a function object) and its parameters, call it and perform the measurement. The return type is that of the original function. Example usage syntax:
Your
measure
is closest to the second variant, the only thing that is wrong with it is the declaration. This is the correct one:To be precise, this is not the only wrong thing. If the measured function returns a reference, the return type will be wrong. To fix this, replace
with
in the body of the lambda
The other thing that is wrong with your program (but not the
measure
itself) is the way you are trying to use a member function.This just doesn't work. Use a lambda or
std::bind
to create a bound member function. There's about a zillion questions (and great answers) about the correct way to do it on stackoverflow.Live demo (with return by reference working).
If you want the first way of creating a measured function, here's how:
Live demo (with return by reference).
Pay special attention to religious use of
decltype(auto)
. Alsomutable
in the second version.