使用C ++ 14 lambda

时间:2018-12-12 07:29:56

标签: c++ lambda c++14 chrono

我对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)...);
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~                

显然我做错了,但我不知道该怎么做。有谁能够帮助我?非常感谢你!

3 个答案:

答案 0 :(得分:2)

有两种方法可以完成此任务。

  1. 接受一个函数(或一个函数对象),返回修改后的函数,该函数执行与原始函数相同的操作,并计算时间。返回的对象类型不能与接受的参数类型相同。它必须是lambda(或自定义类类型,但lambda更简单)。当调用 returned 对象时,将执行实际测量。使用语法示例:

    result = measure(foo)(param1, param2);  // variant 1
    auto measured_foo = measure(foo);
    result = measured_foo(param1, param2);  // variant 2
    
  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上执行此操作的正确方法的疑问不计其数(很好的答案)。

Live demo(通过引用返回)。

如果您想要第一种创建测量函数的方法,请按以下步骤操作:

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(引用返回)。

特别注意decltype(auto)的宗教用途。也是第二版的mutable

答案 1 :(得分:1)

不知道您正在尝试做什么,但是如果您要这样做,我想在这里我已经做了什么:

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

答案 2 :(得分:0)

如果由于某种原因不喜欢采用成员函数的函数指针(请参见here),那么好的旧宏可以助您一臂之力。有些人建议尽量减少对宏的使用,但是在这种情况下,我发现它更加直观,易读和容易。可以使用以下宏对任意函数(包括调用返回类型的类的公共成员函数的调用)进行计时。

#define timefnrt(W, X, Z){\
    time_t V = time(NULL);\
    W = X;\
    time_t Y = time(NULL);\
    Z = difftime(Y, V);\
};

Live code demonstration

如果该函数返回一个void,则可以这样计时:

#define timefnvoid(X, Z){\
    time_t V = time(NULL);\
    X;\
    time_t Y = time(NULL);\
    Z = difftime(Y, V);\
};