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

这适用于返回某些东西(即 not 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;
}

有没有解决的办法?


更新

感谢 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

问题是默认模板参数不能用于不同的模板,就像默认函数参数不能用于不同的重载一样。有一些方法可以解决这个问题,我在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

于 2013-07-19T14:08:49.540 回答