我正在尝试编写一个函数包装器,用于记录和计时; 继这个例子之后,到目前为止我对如何做到这一点有很好的处理:
template <typename R, typename ...Args>
std::function<R(Args...)> logged(string name, std::function<R(Args...)> f)
{
return [f,name](Args... args){
LOG << name << " start" << NL;
auto start = std::chrono::high_resolution_clock::now();
R result = f(std::forward<Args>(args)...);
auto end = std::chrono::high_resolution_clock::now();
auto total = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
LOG << "Elapsed: " << total << "us" << NL;
return result;
};
}
Run Code Online (Sandbox Code Playgroud)
但是,这仅适用于具有非void返回类型的函数.虽然我可以轻松地编写一个副本,用空格(即接收和返回std::function<void(Args...)> f)替换所有"R"实例,但我宁愿避免重复,如果可能的话.有没有办法可以处理R无效的案例?
我试图使用type_traits :: is_void和分支逻辑来处理问题,但我总是会得到错误missing template arguments before ( token if(!is_void(R)::value).
我应该提一下,由于工作场所的限制,我正在使用C++ 11.
您可以使用RAII来使用一个独特的功能:
template <typename F>
struct Finally {
Finally(F f) : f(f) {}
~Finally() { f(); }
Finally(const Finally&) = delete;
Finally& operator=(const Finally&) = delete;
F f;
};
// pre C++17
template <typename F>
Finally<F> make_finally(F f) {
return {f};
}
template <typename R, typename ...Args>
std::function<R(Args...)> logged(string name, std::function<R(Args...)> f)
{
return [f, name](Args... args) -> R {
LOG << name << " start" << NL;
auto start = std::chrono::high_resolution_clock::now();
Finally finally([&](){ // C++17
// auto&& finally = make_finally([&](){ // Pre-C++17
auto end = std::chrono::high_resolution_clock::now();
auto total = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
LOG << "Elapsed: " << total << "us" << NL;
});
return f(std::forward<Args>(args)...);
};
}
Run Code Online (Sandbox Code Playgroud)