Measure execution time of arbitrary functions with C++14 lambda

落爺英雄遲暮 提交于 2019-12-01 06:25:38

There are two ways to approach this task.

  1. 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:

    result = measure(foo)(param1, param2);  // variant 1
    auto measured_foo = measure(foo);
    result = measured_foo(param1, param2);  // variant 2
    
  2. 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:

    result = measure(foo, param1, param2);
    

Your measure is closest to the second variant, the only thing that is wrong with it is the declaration. This is the correct one:

auto measure = [](auto&& function, auto&&... parameters) -> decltype(auto)

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

const auto returnValue = ...

with

decltype(auto) returnValue = ...

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.

Function function = instance.computation;

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:

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;
    };
};

Live demo (with return by reference).

Pay special attention to religious use of decltype(auto). Also mutable in the second version.

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:

#include <chrono>
#include <iostream>
#include <functional>

auto measure = [](auto function, auto&&... parameters) -> decltype(function(parameters...))
{
    const std::chrono::steady_clock::time_point startTimePoint =
    std::chrono::steady_clock::now();

    auto returnValue = function(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;

    auto func = std::bind(&Test::computation, &instance, std::placeholders::_1);

    int result = measure(func, 1.0);

    std::cout << "Result: " << result << std::endl;

    return 0;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!