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が 2 回定義されているとまだ不平を言っています。

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

これを回避する方法はありますか?


アップデート

R. Martinho Fernandes のおかげで、私が現在使用している関数は次のとおりです。

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

1 に答える 1

14

問題は、既定の関数引数が異なるオーバーロードに対して作成されないのと同じように、既定のテンプレート引数が異なるテンプレートに対して作成されないことです。これにはいくつかの方法があり、リマスターされた 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

于 2013-07-19T14:08:49.540 に答える