我正在尝试为日志记录和计时目的编写一个函数包装器;紧随this example之后,到目前为止,我对如何做到这一点非常了解:
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;
};
}
但是,这仅适用于具有非空返回类型的函数。虽然我可以轻松地编写一个副本,用一个空值替换所有“ R”实例(即,采用并返回std::function<void(Args...)> f
),但我还是希望避免重复。有什么方法可以处理R
无效的情况?
我试图使用type_traits :: is_void和分支逻辑来解决问题,但是我总是会收到错误missing template arguments before ( token if(!is_void(R)::value)
。
我应该提到,由于工作场所的限制,我正在使用C ++ 11。
答案 0 :(得分:5)
您可以使用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)...);
};
}