通过参数传递任何函数

Cha*_*ime 6 c++ lambda function

解释

你好,我想创建一个可以执行任何类型函数的函数,在执行结束时指示它所花费的时间。被调用的函数可以有一个或没有返回值,以及 0 个或多个任何类型的参数。

调用函数必须打印如下内容:

Running "myFunction" .....  
Done ! (5210ms)
Run Code Online (Sandbox Code Playgroud)

基本上我想创建一个函数,通过在调用前后添加代码来调用作为参数传递的任何类型的函数。

我做了什么

现在我是这样做的。

调用函数:

Running "myFunction" .....  
Done ! (5210ms)
Run Code Online (Sandbox Code Playgroud)

主要的

template <typename T>
T callFunctionPrintTime(std::string fnName, std::function<T()> fn) {
    std::cout << ">> Running " << fnName << " ... " << std::endl;
    auto t1 = std::chrono::high_resolution_clock::now();

    //Call to the target function
    T retVal = fn();

    auto t2 = std::chrono::high_resolution_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count();

    std::cout << "Done ! (" << duration << " ms)" << std::endl;

    return retVal;
}
Run Code Online (Sandbox Code Playgroud)

myFunction
这个函数没有关系,它可以是任何东西。

在这里,我们在给定的最大时间或最大循环次数内执行 while 循环,并检索执行的循环次数。

int main()
{
    //Store the function to call
    std::function<unsigned long()> fn = []() {
        return myFunction(15, 10000);
    };

    //Use of the function we are interested in
    auto i = callFunctionPrintTime("myFunction", fn);

    //The return value of myFunction can be used in the rest of the program.
    std::cout << "i: " << i << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

你这样做的最佳方法是什么?我对我的代码不满意。
我不确定我是否使用正确的方式通过参数传递任何类型的函数。
此外,通过使用 lambda 表达式来存储我的函数,我无法检索被调用函数的名称。所以我必须通过参数传递它的名字。

Ted*_*gmo 4

我很确定什么是最好的没有单一的答案- 但在我看来这是一个小小的改进,因为它更通用一些。

#include <chrono>
#include <iostream>
#include <string>
#include <type_traits>

// enable it for invocables with any type of arguments
template <class Func, class... Args,
          std::enable_if_t<std::is_invocable_v<Func, Args...>, int> = 0>
decltype(auto) callFunctionPrintTime(std::string fnName, Func fn, Args&&... args)
{
    std::cout << ">> Running " << fnName << " ... " << std::endl;
    auto t1 = std::chrono::high_resolution_clock::now();

    //Call to the target function by forwarding the arguments to it
    decltype(auto) retVal = fn(std::forward<Args>(args)...);

    auto t2 = std::chrono::high_resolution_clock::now();
    auto duration = 
        std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count();

    std::cout << "Done ! (" << duration << " ms)" << std::endl;

    return retVal;
}
Run Code Online (Sandbox Code Playgroud)

或者,如果您不打算对不可调用项进行重载(当我想到这一点时,这似乎很明显您不会这样做),您可以使用static_assert而不是 SFINAE:

template <class Func, class... Args>
decltype(auto) callFunctionPrintTime(std::string fnName, Func fn, Args&&... args)
{
    static_assert(std::is_invocable_v<Func, Args...>, "must be invocable");
    //...
Run Code Online (Sandbox Code Playgroud)

测试用法:

int& a_func(int i) {
    static int rv = 0;
    rv += i;
    return rv;
}


int main() {
    int& ref = callFunctionPrintTime("a_func 1", a_func, 10);
    
    std::cout << ref << '\n';  // prints 10
    
    ref += 20;

    callFunctionPrintTime("a_func 2", a_func, 100);

    std::cout << ref << '\n';  // prints 130 (10 + 20 + 100)
}
Run Code Online (Sandbox Code Playgroud)

或者一些拨打电话的替代方案myFunction

std::function<unsigned long()> fn = []() { return myFunction(15, 100000); };

std::cout << callFunctionPrintTime("myFunction", fn);
Run Code Online (Sandbox Code Playgroud)
std::cout << callFunctionPrintTime("myFunction",
                                   []() { return myFunction(15, 100000); });
Run Code Online (Sandbox Code Playgroud)
std::cout << callFunctionPrintTime("myFunction", myFunction, 15, 100000);
Run Code Online (Sandbox Code Playgroud)

一些有用的链接: decltype(auto)std::enable_if_tstd::is_invocable_vSFINAE