我正在尝试编写一个用于日志记录和计时目的的函数包装器;跟随 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;
};
}
但是,这仅适用于具有非 void 返回类型的函数。虽然我可以轻松编写一个拷贝,用 void 替换“R”的所有实例(即获取并返回 std::function<void(Args...)> f
),但我宁愿尽可能避免重复。有什么方法可以处理 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)...);
};
}
关于c++ - 在模板函数包装器中处理 void 返回,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51678936/