c++ - void 和非 void 返回函数的完美转发

标签 c++ c++11 overloading rvalue-reference

以前,每当我想快速检查时,我都会使用宏来测量函数调用所花费的时间。现在,有了可用的 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;
}

有解决办法吗?


更新

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

最佳答案

问题是默认模板参数不能用于不同的模板,就像默认函数参数不能用于不同的重载一样。有一些方法可以解决这个问题,我在我的 Remastered enable_if 中描述了它们。文章。

但是,我不会那样做。我会简单地利用这样一个事实,即在通用代码中您可以“return void”,并使用 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

关于c++ - void 和非 void 返回函数的完美转发,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17748059/

相关文章:

C++将函数模板作为参数传递给其他函数作为回调

java - Java 中特定于子类的重写

c++ - 在 C++ 中寻找 strtok() 的替代方案

c++ - 为什么我的本地对象被破坏了两次?

c++ - 不可复制和 move 构造函数

Java - 当涉及到继承、多态、重载和覆盖时调用哪个函数?

C++,重载 std::swap,编译器错误,VS 2010

c++ - 如何在其中心旋转二维对象

c++ - 删除第一位

c++11 - react 性扩展中的cpp编译错误