c++ - 任意功能的定时器

标签 c++ templates c++11 variadic-templates c++-chrono

我尝试构建一个可以测量任意类型函数执行时间的函数模板。到目前为止,这是我尝试过的:

#include <chrono>
#include <iostream>
#include <type_traits>
#include <utility>

// Executes fn with arguments args and returns the time needed
// and the result of f if it is not void
template <class Fn, class... Args>
auto timer(Fn fn, Args... args)
    -> std::pair<double, decltype(fn(args...))> {
  static_assert(!std::is_void<decltype(fn(args...))>::value,
                "Call timer_void if return type is void!");
  auto start = std::chrono::high_resolution_clock::now();
  auto ret = fn(args...);
  auto end = std::chrono::high_resolution_clock::now();
  std::chrono::duration<double> elapsed_seconds = end - start;
  return { elapsed_seconds.count(), ret };
}

// If fn returns void, only the time is returned
template <class Fn, class... Args>
double timer_void(Fn fn, Args... args) {
  static_assert(std::is_void<decltype(fn(args...))>::value,
                "Call timer for non void return type");
  auto start = std::chrono::high_resolution_clock::now();
  fn(args...);
  auto end = std::chrono::high_resolution_clock::now();
  std::chrono::duration<double> elapsed_seconds = end - start;
  return elapsed_seconds.count();
}

int main () {
    //This call is ambigous if the templates have the same name
    std::cout << timer([](double a, double b){return a*b;},1,2).first;
}

请注意,我必须为 void(...) 函数设置一个不同名称的函数。有没有办法摆脱第二个功能?

(首先我所做的是正确的吗?)

最佳答案

您可以使用 enable_if 或标签调度。 Enable_if 在这种情况下似乎是更快的方法:

#include <type_traits>

template <class Fn, class... Args>
auto timer(Fn fn, Args && ... args) -> typename std::enable_if< 
    // First template argument is the enable condition
    !std::is_same< 
            decltype( fn( std::forward<Args>(args) ... )), 
            void >::value,
    // Second argument is the actual return type
    std::pair<double, decltype(fn(std::forward<Args>(args)...))> >::type
{
   // Implementation for the non-void case
}

template <class Fn, class... Args>
auto timer(Fn fn, Args &&... args) -> typename std::enable_if< 
    std::is_same< 
            decltype( fn( std::forward<Args>(args) ... )), 
            void >::value,
    double>::type
{
   // Implementation for void case
}

此外,您还应该使用完美转发将参数传递给被调用函数:

 auto timer(Fn fn, Args && ... args) // ...
                      ~~~^   

当你调用这个函数时:

 auto ret = fn( std::forward<Args>(args)...);

Demo .请注意,这适用于函数、lambda 和可调用对象;几乎所有东西都带有 operator()

从设计的角度来看,我认为返回 std::pair 没有问题。由于 C++11 具有 std::tie,因此返回一个 pair/tuple 是从一个函数返回多个结果的合法方式。我会继续说,为了在 void 情况下保持一致,您应该返回一个只有一个元素的元组。

关于c++ - 任意功能的定时器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24468397/

相关文章:

C++11 正则表达式细节

c++11 - 在 vector::emplace_back 中就地构造 std::pair

c++ - 使用分配器替代 malloc()/free()?

java - Windows C++ 相当于 Java 的 LockSupport.parkNanos()

c++ - 麻省理工学院球体模拟设置中的 Matlab 错误

c++ - 两种类型的模板特化

c++ - 模板类看不到继承的模板成员

c++ - 签名到未签名的类型转换

c++ - 以可变类模板作为函数调用参数的函数模板参数推导

c++ - 如何将二进制数据硬编码为字符串