2013-07-19 33 views
9

以前我使用宏來測量函數調用每當我想快速檢查時所花費的時間。現在,C++提供11,我想最後取出的預處理程序代碼醜陋和平和替換它是這樣的:完美轉發無效和無效返回函數

template <typename Functor, typename ... Args> 
auto measure(Functor f, Args && ... args) 
    -> decltype(f(std::forward<Args>(args)...)) 
{ 
    auto now = std::chrono::high_resolution_clock::now(); 
    auto ret = f(std::forward<Args>(args)...); 
    auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
     std::chrono::high_resolution_clock::now() - now).count(); 
    std::cout << "Time elapsed: " << elapsed << "ms" << std::endl; 

    return ret; 
} 

這對於返回的東西(即不void)功能工作正常。所以我覺得我需要一個void函數的重載 - 但是你不能在返回類型上重載一個函數。

我試着用一些模板魔法繞過這個問題,但無濟於事;編譯器仍然抱怨說,功能measure定義兩次:

template < 
    typename Functor, typename ... Args, 
    typename ReturnType = typename std::enable_if< 
     !std::is_void< 
      typename std::result_of<Functor(Args...)>::type 
     >::value, 
     typename std::result_of<Functor(Args...)>::type 
    >::type 
> 
ReturnType measure(Functor f, Args && ... args) 
{ 
    auto now = std::chrono::high_resolution_clock::now(); 
    auto ret = f(std::forward<Args>(args)...); 
    auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
     std::chrono::high_resolution_clock::now() - now).count(); 
    std::cout << "Time elapsed: " << elapsed << "ms" << std::endl; 

    return ret; 
} 

template < 
    typename Functor, typename ... Args, 
    typename ReturnType = typename std::enable_if< 
     std::is_void< 
      typename std::result_of<Functor(Args...)>::type 
     >::value 
    >::type 
> 
ReturnType measure(Functor f, Args && ... args) 
{ 
    auto now = std::chrono::high_resolution_clock::now(); 
    f(std::forward<Args>(args)...); 
    auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
     std::chrono::high_resolution_clock::now() - now).count(); 
    std::cout << "Time elapsed: " << elapsed << "ms" << std::endl; 
} 

有沒有辦法解決?


UPDATE

這裏是我現在用的感謝R.費爾南德斯Martinho功能:

template <typename Functor, typename ... Args> 
auto measure(Functor f, Args && ... args) 
    -> decltype(f(std::forward<Args>(args)...)) 
{ 
    struct scoped_timer 
    { 
     scoped_timer() : now_(std::chrono::high_resolution_clock::now()) {} 
     ~scoped_timer() 
     { 
      auto elapsed = std::chrono::duration_cast< 
        std::chrono::milliseconds 
       >(std::chrono::high_resolution_clock::now() - now_).count(); 
      std::cout << "Time elapsed: " << elapsed << "ms" << std::endl; 
     } 

     private: 
      std::chrono::high_resolution_clock::time_point const now_; 
    } scoped_timer; 

    return f(std::forward<Args>(args)...); 
} 
+0

請參閱http://flamingdangerzone.com/cxx11/2012/06/01/almost-static-if.html#evolution –

+0

高雅[idea](http://stackoverflow.com/a/17748197/1137388)( [R. Martinho Fernandes](http://stackoverflow.com/users/46642/r-martinho-fernandes))。我所做的唯一改變就是將'〜scoped_timer()'的代碼放在一個'try-catch'塊中,以避免拋出任何異常。在語義上,我相信如果不成功完成,不報告'f'運行的時間是有意義的。不幸的是,這對於'<<'拋出的可能異常並不那麼明顯。一個老的'printf'會是一個更好的選擇(關於異常安全)?我不知道。 –

回答

14

的問題是,默認模板參數不作不同的模板,與缺省函數參數不會針對不同重載的方式相同。有一些解決方法,我在Remastered enable_if文章中描述了它們。

但是,我不會那樣做。我只想利用的事實,即在通用的代碼,你可以「return作廢」,並使用RAII打印出經過的時間:

template <typename Functor, typename ... Args> 
auto measure(Functor f, Args && ... args) 
    -> decltype(f(std::forward<Args>(args)...)) 
{ 
    scoped_timer timer; 
    return f(std::forward<Args>(args)...); 
} 

scoped_timer類可以平凡寫:保存now在構造函數中,並在析構函數中計算並輸出elapsed

+0

實際上,我之前做過類似這樣的事情,而我只是完全放棄了結果值,而是用'measure'來代替經過的時間。 –

+0

您的文章是一個令人難以置信的有趣的閱讀。謝謝。我仍想返回函數最初返回的值,但是您的解決方案對此很有幫助。 – user2573221