В Python существует очень простой способ декорирования функции, позволяющей добавлять дополнительные функции до и/или после функции. В своей самой простой форме это выглядит следующим образом:Вложенные функции шаблонов как параметры
from random import SystemRandom
from 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) for _ in range(10000)]
sorted(x)
foo() # prints "Took 0.04239s"
Я хотел написать что-то с подобной функциональностью в C++. Я хотел бы передать функцию с произвольными параметрами и возвращать типы в функцию и выполнить какое-либо действие. Это то, что я придумал:
#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> // this is required for any 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> // this is for any 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
Это работает довольно хорошо. Например, я могу время в основном любую функции со следующим:
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;
}
Проблема возникает, когда я пытаюсь время шаблонной функции, такие как std::sort
непосредственно. Я могу сделать это только в том случае, если я укажу точный тип. Я предположил, что мне интересно, способен ли C++ делать вложенные шаблонные вычеты. Я хочу, чтобы вывести какую форму станд :: сортировать Я использую и изменить реализацию t_sort динамически:
Что я сейчас делаю:
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());
}
Что я хотел бы:
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); // this line is different
unsigned long sort_time = 0;
t_sort(sort_time, nums.begin(), nums.end());
}
Возможно ли это? Моя первоначальная реакция, вероятно, нет, но если нет, то почему?
Как насчет 'timer ([&]() {return std :: sort (nums.begin(), nums.end());});' синтаксис? – Jarod42
Я не обязательно против, но я думаю, что это делает его немного менее питоническим. Я знаю, что это ужасный, ужасный способ взглянуть на него, но мне нравится простота обертывания функции. Я полагаю, что мой вопрос заключается в том, может ли быть дедукция при использовании функции t_sort, а не при передаче в std :: sort. – Goodies
Однако похоже, что я нашел ответ на свой вопрос: http://www.open-std.org/jtc1/sc22/wg21/docs/wp/html/oct97/template.html#temp.arg.template – Goodies