我尝试构建一个函数模板,可以测量任意类型函数的执行时间.这是我到目前为止所尝试的:
#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,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,Args &&... args) -> typename std::enable_if< std::is_same< decltype( fn( std::forward<Args>(args) ... )),double>::type { // Implementation for void case }
auto timer(Fn fn,Args && ... args) // ... ~~~^
auto ret = fn( std::forward<Args>(args)...);
Demo.请注意,这适用于函数,lambda和可调用对象;几乎所有的东西都有一个operator().
从设计的角度来看,我发现返回std ::对没有问题.由于C 11具有std :: tie,因此返回一对/元组是从函数返回多个结果的合法方式.我会继续说,为了在void情况下保持一致,你应该返回一个只有一个元素的元组.