对任何其他任意函数及其结果进行计时的函数 return
A function to time any other arbitrary function and return its results
我正在尝试编写一个函数,它接受任何其他任意函数作为输入并对其计时,然后 returns 该函数的结果。我已经用了几个小时了,我觉得我已经很接近了,但我仍然不太清楚如何让它编译。
这是我目前拥有的:
// 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);
}
我的处理方式是否正确?如果是这样,我需要更改什么才能使其正常工作?如果没有,解决这个问题的更好方法是什么?
这里的问题是 T
在你的函数中是不可推导的。您分配给 return 的值不参与模板参数推导。要按原样使用它,您需要使用
指定 return 类型
int output = GetRuntime<int>("DoSomething", DoSomething, 42, 42.42);
^^^ specify T is an int
但是我们可以通过对函数的 return 类型使用 auto
来改善这一点。使用它将函数变成
template <typename Function, typename... Args>
auto GetRuntime(const std::string& name, const Function& function, Args&&... args)
{
std::cout << name << " started..." << std::endl;
auto start = std::chrono::high_resolution_clock::now();
auto 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;
}
编译器无法推断 T
。这是一个模板参数,但您的参数中没有任何内容可以推断它。
但是,您可以使用 std::invoke_result
获取函数的 return 类型:
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 {
// ...
}
NathanOliver 已经给出了正确答案。这只是关于如何使功能更通用的答案。它也适用于 void
函数,并且不进行任何日志记录。它 return 是一个包含持续时间和传递函数的 return 值的元组。如果传递的函数 returns void
,它只是直接 returns 持续时间(没有元组。)
(这都是 C++17。)
// 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";
对于非 void 函数,您使用结构化绑定:
auto [duration, int_val] = GetRunTime(int_func, arg1, arg2);
cout << "Took " << duration.count() << "ms and returned " << int_val << '\n';
您的原始日志记录功能可以作为 GetRuntime()
的包装器实现。 return 日志函数的类型将与传递函数的类型相同:
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);
}
}
我正在尝试编写一个函数,它接受任何其他任意函数作为输入并对其计时,然后 returns 该函数的结果。我已经用了几个小时了,我觉得我已经很接近了,但我仍然不太清楚如何让它编译。
这是我目前拥有的:
// 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);
}
我的处理方式是否正确?如果是这样,我需要更改什么才能使其正常工作?如果没有,解决这个问题的更好方法是什么?
这里的问题是 T
在你的函数中是不可推导的。您分配给 return 的值不参与模板参数推导。要按原样使用它,您需要使用
int output = GetRuntime<int>("DoSomething", DoSomething, 42, 42.42);
^^^ specify T is an int
但是我们可以通过对函数的 return 类型使用 auto
来改善这一点。使用它将函数变成
template <typename Function, typename... Args>
auto GetRuntime(const std::string& name, const Function& function, Args&&... args)
{
std::cout << name << " started..." << std::endl;
auto start = std::chrono::high_resolution_clock::now();
auto 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;
}
编译器无法推断 T
。这是一个模板参数,但您的参数中没有任何内容可以推断它。
但是,您可以使用 std::invoke_result
获取函数的 return 类型:
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 {
// ...
}
NathanOliver 已经给出了正确答案。这只是关于如何使功能更通用的答案。它也适用于 void
函数,并且不进行任何日志记录。它 return 是一个包含持续时间和传递函数的 return 值的元组。如果传递的函数 returns void
,它只是直接 returns 持续时间(没有元组。)
(这都是 C++17。)
// 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";
对于非 void 函数,您使用结构化绑定:
auto [duration, int_val] = GetRunTime(int_func, arg1, arg2);
cout << "Took " << duration.count() << "ms and returned " << int_val << '\n';
您的原始日志记录功能可以作为 GetRuntime()
的包装器实现。 return 日志函数的类型将与传递函数的类型相同:
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);
}
}