代码之家  ›  专栏  ›  技术社区  ›  Brandon McKenzie

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

c++
  •  2
  • Brandon McKenzie  · 技术社区  · 8 年前

    我试图编写一个用于日志记录和计时的函数包装器;下面是 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返回类型的函数。虽然我可以很容易地写一个副本,用一个空的替换所有“R”的实例(即take和returns std::function<void(Args...)> f ),如果可能的话,我宁愿避免重复。我有办法处理 R 是空的吗?

    我曾试图使用type_traits::is_void和分支逻辑来处理这个问题,但是我总是会得到错误 missing template arguments before ( token if(!is_void(R)::value) .

    我要提到的是,由于工作场所的限制,我正在使用C++ 11。

    1 回复  |  直到 8 年前
        1
  •  5
  •   Jarod42    8 年前

    您可以使用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)...);
        };
    }