在模板函数包装器中处理void返回

时间:2018-08-03 19:24:03

标签: c++

我正在尝试为日志记录和计时目的编写一个函数包装器;紧随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。

1 个答案:

答案 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)...);
    };
}