python - Nested Template Functions as Parameters -
in python, there way of decorating function such can add additional functionality before and/or after function. in simple form, looks this:
from random import systemrandom time import time import functools rdev = systemrandom() def time_function(func): @functools.wraps(func) def run(*args, **kwargs): start = time() ret = func(*args, **kwargs) print("took {:0.5f}s".format(time()-start)) return ret return run @time_function def foo(): x = [rdev.randint(1, 1000) _ in range(10000)] sorted(x) foo() # prints "took 0.04239s"
i wanted write similar functionality in c++. pass function arbitrary parameters , return types function , have perform action. came with:
#ifndef timeit_h #define timeit_h #include <string> #include <functional> #include <iostream> #if defined(_win32) #include <windows.h> namespace timeit { unsigned long gettime(void) { return gettickcount(); } } #elif defined(__linux__) namespace timeit{ unsigned long gettime(void) { return 0; // implement later } } #endif namespace timeit { template <typename> struct timer_s; template<typename... args> // required void function struct timer_s<void(args ...)> { std::function<void(args ...)> func; timer_s(std::function<void(args ...)> f) : func{ f } {} void operator()(unsigned long &time, args ... args) { unsigned long start = gettime(); func(args ...); time = gettime() - start; return; } }; template <typename t, typename... args> // other return type struct timer_s<t(args ...)> { std::function<t(args ...)> func; timer_s(std::function<t(args ...)> f) : func{ f } { } t operator()(unsigned long &time, args ... args) { unsigned long start = gettime(); t ret = func(args ...); time = gettime() - start; return ret; } }; template<typename t, typename... args> timer_s<t(args...)> timer(t(*func)(args ...)) { return timer_s<t(args ...)>(std::function<t(args ...)>(func)); } } #endif//timeit_h
this working rather well. example, can time function following:
static std::random_device rdev; unsigned int foo(size_t size){ std::vector<unsigned int> nums(size); std::mt19937 rand(rdev()); std::generate(nums.begin(), nums.end(), rand); std::sort(nums.begin(), nums.end()); return nums.back(); // return largest number } int main(){ //foo(0xffff); // normal call unsigned long foo_time = 0; auto t_foo = timeit::timer(foo); unsigned int largest = t_foo(foo_time, 0xffff); // stores time std::cout << "took " << foo_time << "ms\nlargest number: " << largest << "\n"; return 0; }
the trouble arises when try time templated function such std::sort
directly. can if specify exact type. supposed wondering if c++ capable of doing nested template deduction. want deduce form of std::sort using , change implementation of t_sort dynamically:
what doing:
static std::random_device rdev; int main(){ std::vector<unsigned int> nums(size); std::mt19937 rand(rdev()); std::generate(nums.begin(), nums.end(), rand); auto t_sort = timeit::timer(std::sort<std::vector<unsigned int>::iterator>); unsigned long sort_time = 0; t_sort(sort_time, nums.begin(), nums.end()); }
what like:
static std::random_device rdev; int main(){ std::vector<unsigned int> nums(size); std::mt19937 rand(rdev()); std::generate(nums.begin(), nums.end(), rand); auto t_sort = timeit::timer(std::sort); // line different unsigned long sort_time = 0; t_sort(sort_time, nums.begin(), nums.end()); }
is possible? initial reaction not, if not, why?
std::sort
not function function template,
one solution accept functor instead:
namespace timeit { template <typename functor> struct timer_s { functor func; double time = 0; timer_s(functor f) : func{ f } {} template <typename ... ts> auto operator()(ts ... args) { struct { ~finally() { time = std::chrono::duration_cast<std::chrono::milliseconds> (std::chrono::system_clock::now() - start).count(); } double& time; std::chrono::time_point<std::chrono::system_clock> start; } finally{time, std::chrono::system_clock::now()}; return func(std::forward<ts>(args)...); } }; template<typename f> timer_s<f> timer(f f) { return timer_s<f>(f); } }
and call it:
// generic lambda wrap std::sort , call correct one. auto t_sort = timeit::timer([](auto b, auto e){ return std::sort(b, e); }); std::vector<int> v {4, 8, 23, 42, 15, 16}; t_sort(v.begin(), v.end());
Comments
Post a Comment