我正在尝试编写一个模板,该模板将采用任何函数并记录其时间,并且在使用模板语法进行了一些努力之后,我提出了以下解决方案:
template <typename Func, typename... Args>
auto timeMyFunction(Func f, Args... args)-> typename
std::enable_if<std::is_same<decltype(f(args...)),void>::value,void>::type
{
auto start = std::chrono::steady_clock::now();
f(args...);
auto end = std::chrono::steady_clock::now();
std::chrono::duration<double> diff = end-start;
std::cout << "Time to complete function " << diff.count()<<std::endl;
}
template <typename Func, typename... Args>
auto timeMyFunction(Func f, Args... args)-> typename std::enable_if<!std::is_same<decltype(f(args...)),void>::value,decltype(f(args...))>::type
{
auto start = std::chrono::steady_clock::now();
auto ret = f(args...);
auto end = std::chrono::steady_clock::now();
std::chrono::duration<double> diff = end-start;
std::cout << "Time to complete function " << diff.count()<<std::endl;
return ret;
}
但我觉得这个解决方案是某种Jugaad(https://en.wikipedia.org/wiki/Jugaad),需要你的帮助才能找到更好的解决方案。所以我正在寻找的是计算传递函数的处理时间的模板,如果可能的话可以在没有重载的情况下完成,因为我需要重载,因为我不能声明像void ret
这样的东西。我在这里使用decltype
也是正确的。
请建议如何修改它,以便我也可以通过此模板计时类成员和静态功能。
答案 0 :(得分:4)
将时间计算/显示包装在一个类中:
class TimerDisplayer
{
public:
TimerDisplayer() {}
~TimerDisplayer()
{
auto end = std::chrono::steady_clock::now();
std::chrono::duration<double> diff = end - start;
std::cout << "Time to complete function " << diff.count() << std::endl;
}
std::chrono::time_point<std::chrono::steady_clock> start =
std::chrono::steady_clock::now();
};
然后
template <typename Func, typename... Args>
decltype(auto) timeMyFunction(Func&& f, Args&&... args)
{
TimerDisplayer timerDisplay;
return std::forward<Func>(f)(std::forward<Args>(args)...);
}
答案 1 :(得分:1)
不是一个很好的解决方案,但是......如果返回类型不是exec
,您可以使用返回值f(args...)
的方法创建模板void
结构,或者一个假值(例如int
),否则。
以示例
template <typename RetType>
struct execStruct
{
template <typename Func, typename ... Args>
static constexpr RetType exec (Func f, Args ... as)
{ return f(as...); }
};
template <>
struct execStruct<void>
{
template <typename Func, typename ... Args>
static constexpr int exec (Func f, Args ... as)
{ return (void)f(as...), 0; }
};
因此,您可以检测返回类型(RetType
,在以下示例中),保存execStruct::exec(f, args...)
返回的值(伪值,在void情况下)并返回保存的值,将其转换为retType
。因此,如果RetType
为void
,则将假值转换为void
就像撰写return;
一样。
以下是一个完整的工作示例
#include <chrono>
#include <utility>
#include <iostream>
#include <functional>
template <typename RetType>
struct execStruct
{
template <typename Func, typename ... Args>
static constexpr RetType exec (Func f, Args ... as)
{ return f(as...); }
};
template <>
struct execStruct<void>
{
template <typename Func, typename ... Args>
static constexpr int exec (Func f, Args ... as)
{ return (void)f(as...), 0; }
};
template <typename Func, typename ... Args>
auto timeMyFunc (Func f, Args ... args) -> decltype( f(args...) )
{
using RetType = decltype( f(args...) );
auto start = std::chrono::steady_clock::now();
auto ret = execStruct<RetType>::exec(f, args...);
auto end = std::chrono::steady_clock::now();
std::chrono::duration<double> diff = end-start;
std::cout << "Time to complete function " << diff.count()<<std::endl;
return RetType(ret);
}
static int foo1 (int, int)
{ return 42; }
void foo2 (std::string const &)
{ }
struct foo3
{
static std::string bar1 (long)
{ return "abc"; }
long bar2 (std::string const &)
{ return 0L; }
};
int main ()
{
using namespace std::placeholders;
foo3 f3;
auto f3b2a = std::bind(&foo3::bar2, &f3, _1);
auto f3b2b
= std::function<long(foo3 &, std::string const &)>(&foo3::bar2);
using foo1Type = decltype(timeMyFunc(foo1, 1, 2));
using foo2Type = decltype(timeMyFunc(foo2, "baz1"));
using bar1Type = decltype(timeMyFunc(foo3::bar1, 3L));
using bar2aType = decltype(timeMyFunc(f3b2a, "baz2"));
using bar2bType = decltype(timeMyFunc(f3b2b, f3, "baz3"));
static_assert(std::is_same<foo1Type, int>::value, "!");
static_assert(std::is_same<foo2Type, void>::value, "!");
static_assert(std::is_same<bar1Type, std::string>::value, "!");
static_assert(std::is_same<bar2aType, long>::value, "!");
static_assert(std::is_same<bar2bType, long>::value, "!");
std::cout << "- " << timeMyFunc(foo1, 1, 2) << std::endl;
timeMyFunc(foo2, "baz");
std::cout << "- " << timeMyFunc(foo3::bar1, 3L) << std::endl;
std::cout << "- " << timeMyFunc(f3b2a, "baz2") << std::endl;
std::cout << "- " << timeMyFunc(f3b2b, f3, "baz3") << std::endl;
}