2013-07-19 13 views
9

これまで、関数呼び出しが時間を測定するためにマクロを使用していました。何か(すなわちないvoid)を返す関数のために正常に動作しますvoidとvoid以外の戻り関数のための完全な転送

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; 
} 

:今、利用できるC++ 11で、私は最終的にプリプロセッサコードの醜い平和を削除して、このようなものと交換したいと思います。だから、私はvoid関数のオーバーロードが必要だと感じましたが、戻り値の型の関数をオーバーロードすることはできません。

私はいくつかのテンプレートマジックを使ってこの問題を回避しようとしましたが、役に立たなかった。

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; 
} 

はこれを回避する方法はあります:コンパイラはまだ機能measureが2回定義されていることを訴えますか?


UPDATE

ここで私は今R.マルティーニ・フェルナンデスへの感謝を使用しています関数です。

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

エレガントな[アイデア](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

関連する問題