Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/155.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 函数对任何其他任意函数计时并返回其结果_C++_Templates_Generic Programming - Fatal编程技术网

C++ 函数对任何其他任意函数计时并返回其结果

C++ 函数对任何其他任意函数计时并返回其结果,c++,templates,generic-programming,C++,Templates,Generic Programming,我试图编写一个函数,它接受任何其他任意函数作为输入,并对其进行计时,然后返回该函数的结果。我已经做了几个小时了,我想我已经很接近了,但是我仍然不知道如何编译它 这就是我到目前为止所做的: // Some arbitrary function to pass to the timer int DoSomething(int x, double y) { // Does something with x and y return 0; } // Function used to t

我试图编写一个函数,它接受任何其他任意函数作为输入,并对其进行计时,然后返回该函数的结果。我已经做了几个小时了,我想我已经很接近了,但是我仍然不知道如何编译它

这就是我到目前为止所做的:

// Some arbitrary function to pass to the timer
int DoSomething(int x, double y)
{
    // Does something with x and y
    return 0;
}

// Function used to time another function and return its result
template <typename T, typename Function, typename... Args>
T GetRuntime(const std::string& name, const Function& function, Args&&... args)
{
    std::cout << name << " started..." << std::endl;
    auto start = std::chrono::high_resolution_clock::now();

    T result = function(std::forward<Args>(args)...);

    auto stop = std::chrono::high_resolution_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(stop - start);
    std::cout << name << " complete - duration: " << duration.count() << " milliseconds." << std::endl;

    return result;
}

int main()
{
    // Doesn't compile
    int output = GetRuntime("DoSomething", DoSomething, 42, 42.42);
}
//要传递给计时器的任意函数
整数剂量测量(整数x,双y)
{
//对x和y做些什么
返回0;
}
//函数用于对另一个函数计时并返回其结果
模板
GetRuntime(常量std::字符串和名称、常量函数和函数、参数和…参数)
{

std::cout这里的问题是,
T
在您的函数中是不可推断的。您分配返回的值不参与模板参数推断。要按原样使用它,您需要使用指定返回类型

int output = GetRuntime<int>("DoSomething", DoSomething, 42, 42.42);
                        ^^^ specify T is an int

编译器无法推断
T
。这是一个模板参数,但您的参数中没有可以推断它的内容

但是,您可以使用
std::invoke_result
获取函数的返回类型:

template <typename Function, typename... Args, typename R = std::invoke_result_t<Function, Args...>>
auto GetRuntime(const std::string& name, const Function& function, Args&&... args) -> R {
    // ...
}
template <typename Function, typename... Args>
auto LogRuntime(const std::string& name, const Function& function, Args&&... args)
{
    std::cout << name << " starting..." << std::endl;
    auto result = GetRuntime(function, std::forward<Args>(args)...);
    std::cout << name << " complete - duration: ";
    constexpr auto is_void = std::is_same_v<decltype(function(args...)), void>;
    if constexpr (is_void) {
        std::cout << result.count();
    } else {
        std::cout << std::get<0>(result).count();
    }
    std::cout << " milliseconds.\n";
    if constexpr (!is_void) {
        return std::get<1>(result);
    }
}
模板
自动获取运行时(const std::string&name,const Function&Function,Args&…Args)->R{
// ...
}

NathanOliver已经给出了正确的答案。这只是一个关于如何使函数更通用的答案。它也与
void
函数一起工作,不做任何日志记录。它返回一个包含传递函数的持续时间和返回值的元组。如果传递的函数返回
void
,它只返回s直接表示持续时间(无元组)

(这都是C++17。)


通过创建一个作用域计时器,并将其添加到要调用的函数的顶部,您可以执行稍微不同的操作。构造函数将启动计时器,析构函数将停止计时器并打印持续时间。在函数开始时,您需要编写的唯一代码是
ScopedTimer timer()如果
函数
返回
void
,则
将不起作用。将所有计时器内容移动到帮助器类的构造函数和析构函数中。在
GetRuntime
中构造帮助器类,然后
返回函数(std::forward(args)…)如果
函数
返回
void
@SamVarshavchik好的点,则
也会起作用。如果这是他们想要的,我会让OP来实现。我想我能处理。总的来说,这是一个很好的答案。我尝试了一下,现在就编译。将其标记为已接受。@tjwrona1992听起来不错,谢谢。如果需要帮助,mak要使其更通用,只需问一个后续问题。似乎即使在建议更改为使用帮助器类后,它仍然无法处理void函数。我进行了更改,并尝试传入void函数,但得到了“致命错误C1001:编译器中发生了内部错误”…感谢Microsoft提供了完全无用的错误消息!为什么这里的
R
是一个模板参数,而不是在尾部返回类型中直接使用
std::invoke_result\u t
?@KonradRudolph只是因为OP似乎想使用名称而不是
auto
,SFINAE@GuillaumeRacicot那只是因为我不知道我不知道我在做什么哈哈哈
// Need these includes in addition to what you already include.
#include <tuple>
#include <type_traits>

template <typename Function, typename... Args>
auto GetRuntime(const Function& function, Args&&... args)
{
    auto start = std::chrono::high_resolution_clock::now();

    if constexpr (std::is_same_v<decltype(function(args...)), void>) {
        function(std::forward<Args>(args)...);
        return std::chrono::duration_cast<std::chrono::milliseconds>(
            std::chrono::high_resolution_clock::now() - start);
    } else {
        auto&& func_result{function(std::forward<Args>(args)...)};
        return std::make_tuple(
            std::chrono::duration_cast<std::chrono::milliseconds>(
                std::chrono::high_resolution_clock::now() - start),
                std::forward<decltype(function(args...))>(func_result));
    }
}
auto duration = GetRunTime(void_func, arg1, arg2);
cout << "Took " << duration.count() << "ms.\n";
auto [duration, int_val] = GetRunTime(int_func, arg1, arg2);
cout << "Took " << duration.count() << "ms and returned " << int_val << '\n';
template <typename Function, typename... Args>
auto LogRuntime(const std::string& name, const Function& function, Args&&... args)
{
    std::cout << name << " starting..." << std::endl;
    auto result = GetRuntime(function, std::forward<Args>(args)...);
    std::cout << name << " complete - duration: ";
    constexpr auto is_void = std::is_same_v<decltype(function(args...)), void>;
    if constexpr (is_void) {
        std::cout << result.count();
    } else {
        std::cout << std::get<0>(result).count();
    }
    std::cout << " milliseconds.\n";
    if constexpr (!is_void) {
        return std::get<1>(result);
    }
}