#include <type_traits>
#include <iostream>
#include <chrono>
using namespace std;
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,
std::pair<double, decltype(fn(args...))> >::type
{
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>
auto timer(Fn fn, Args && ... args) -> typename std::enable_if<
std::is_same< decltype( fn( std::forward<Args>(args) ... )), void >::value,
double>::type
{
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;
}
CiNpbmNsdWRlIDx0eXBlX3RyYWl0cz4KI2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8Y2hyb25vPgp1c2luZyBuYW1lc3BhY2Ugc3RkOwoKdGVtcGxhdGUgPGNsYXNzIEZuLCBjbGFzcy4uLiBBcmdzPgphdXRvIHRpbWVyKEZuIGZuLCBBcmdzICYmIC4uLiBhcmdzKQogICAgLT4gdHlwZW5hbWUgc3RkOjplbmFibGVfaWY8IAogICAgCSFzdGQ6OmlzX3NhbWU8IGRlY2x0eXBlKCBmbiggc3RkOjpmb3J3YXJkPEFyZ3M+KGFyZ3MpIC4uLiApKSwgdm9pZCA+Ojp2YWx1ZSwKICAgIAlzdGQ6OnBhaXI8ZG91YmxlLCBkZWNsdHlwZShmbihhcmdzLi4uKSk+ID46OnR5cGUKewogIHN0YXRpY19hc3NlcnQoIXN0ZDo6aXNfdm9pZDxkZWNsdHlwZShmbihhcmdzLi4uKSk+Ojp2YWx1ZSwKICAgICAgICAgICAgICAgICJDYWxsIHRpbWVyX3ZvaWQgaWYgcmV0dXJuIHR5cGUgaXMgdm9pZCEiKTsKICBhdXRvIHN0YXJ0ID0gc3RkOjpjaHJvbm86OmhpZ2hfcmVzb2x1dGlvbl9jbG9jazo6bm93KCk7CiAgYXV0byByZXQgPSBmbihhcmdzLi4uKTsKICBhdXRvIGVuZCA9IHN0ZDo6Y2hyb25vOjpoaWdoX3Jlc29sdXRpb25fY2xvY2s6Om5vdygpOwogIHN0ZDo6Y2hyb25vOjpkdXJhdGlvbjxkb3VibGU+IGVsYXBzZWRfc2Vjb25kcyA9IGVuZCAtIHN0YXJ0OwogIHJldHVybiB7IGVsYXBzZWRfc2Vjb25kcy5jb3VudCgpLCByZXQgfTsKfQoKLy8gSWYgZm4gcmV0dXJucyB2b2lkLCBvbmx5IHRoZSB0aW1lIGlzIHJldHVybmVkCnRlbXBsYXRlIDxjbGFzcyBGbiwgY2xhc3MgLi4uIEFyZ3M+CmF1dG8gdGltZXIoRm4gZm4sIEFyZ3MgJiYgLi4uIGFyZ3MpIC0+IHR5cGVuYW1lIHN0ZDo6ZW5hYmxlX2lmPCAKICAgIAlzdGQ6OmlzX3NhbWU8IGRlY2x0eXBlKCBmbiggc3RkOjpmb3J3YXJkPEFyZ3M+KGFyZ3MpIC4uLiApKSwgdm9pZCA+Ojp2YWx1ZSwKICAgIAlkb3VibGU+Ojp0eXBlCnsKICBzdGF0aWNfYXNzZXJ0KHN0ZDo6aXNfdm9pZDxkZWNsdHlwZShmbihhcmdzLi4uKSk+Ojp2YWx1ZSwKICAgICAgICAgICAgICAgICJDYWxsIHRpbWVyIGZvciBub24gdm9pZCByZXR1cm4gdHlwZSIpOwogIGF1dG8gc3RhcnQgPSBzdGQ6OmNocm9ubzo6aGlnaF9yZXNvbHV0aW9uX2Nsb2NrOjpub3coKTsKICBmbihhcmdzLi4uKTsKICBhdXRvIGVuZCA9IHN0ZDo6Y2hyb25vOjpoaWdoX3Jlc29sdXRpb25fY2xvY2s6Om5vdygpOwogIHN0ZDo6Y2hyb25vOjpkdXJhdGlvbjxkb3VibGU+IGVsYXBzZWRfc2Vjb25kcyA9IGVuZCAtIHN0YXJ0OwogIHJldHVybiBlbGFwc2VkX3NlY29uZHMuY291bnQoKTsKfQoKCgppbnQgbWFpbiAoKSB7CiAgICAvL1RoaXMgY2FsbCBpcyBhbWJpZ291cyBpZiB0aGUgdGVtcGxhdGVzIGhhdmUgdGhlIHNhbWUgbmFtZQogICAgc3RkOjpjb3V0IDw8IHRpbWVyKFtdKGRvdWJsZSBhLCBkb3VibGUgYil7cmV0dXJuIGEqYjt9LDEsMikuZmlyc3Q7Cn0K