我正在将Python指标库移植到C ++。 Python库提供的一个API是一个函数修饰器,可以轻松地在函数上记录时序数据。通过将函数定义修改为
@timed('timing.foo')
def foo():
...
foo_result = foo()
基本上变成了
start = time.time()
foo_result = foo()
post_metric_to_endpoint('timing.foo', time.time() - start)
在Function hooking in C++中,我们发现this answer包装实例并将调用定时函数的负担放在调用者上,这意味着我们不会在代码库中获取性能数据(更新很烦人)首先,后来很容易忘记)。同样,this answer到Timing in an elegant way in c++也需要更改呼叫网站。这个问题的This other answer提供了一种包装任意代码块的方法,理论上这意味着我们可以缩进我们想要计时的函数的整个主体并将其嵌入到作用域中。这是我发现的最接近我想要的东西,但是非常丑陋,相当干扰,而且我不确定对性能的影响。
由于这是用作库,我们可以修改我们想要的函数的来源;事实上,这是更可取的,因为我希望对该函数的每个调用进行定时。大多数讨论似乎都侧重于开发中的临时分析,而我正在尝试构建一个在生产环境中始终处于活动状态的系统。
答案 0 :(得分:9)
虽然C ++没有对装饰器的显式语言支持,但事实证明你可以使用C ++ 14通用lambda非常好地“模拟”它们。以下是我的看法:
#include <iostream>
template<class T>
auto decorator(T&& func)
{
// we create a closure below
auto new_function = [func = std::forward<T>(func)](auto&&... args)
{
std::cout << "BEGIN decorating...\n";
auto result = func(std::forward<decltype(args)>(args)...);
std::cout << "END decorating\n";
return result;
};
return new_function;
}
int f(int x)
{
std::cout << x * x << '\n';
return x * x;
}
auto decorated = decorator(f);
auto double_decorated = decorator(decorator(f));
int main()
{
decorated(5);
double_decorated(10);
}
当然在装饰者里面你可以添加你想要的任何东西(包括时间等),上面只是一个最小的例子。
如果它看起来太令人生畏,你可以忽略mumbo-jumbo std::forward
和C ++ 14广义lambda捕获并简单地拥有
#include <iostream>
template<class T>
auto decorator(T func)
{
// we create a closure below
auto new_function = [func](auto... args)
{
std::cout << "BEGIN decorating...\n";
auto result = func(args...);
std::cout << "END decorating\n";
return result;
};
return new_function;
}
int f(int x)
{
std::cout << x * x << '\n';
return x * x;
}
auto decorated = decorator(f);
auto double_decorated = decorator(decorator(f));
int main()
{
decorated(5);
double_decorated(10);
}
答案 1 :(得分:2)
C ++没有Pythonic修饰符,但它具有确定性破坏。要对函数计时,请创建一个在构造时捕获时间戳的类,并在销毁时报告。然后将实例声明为函数中的第一行:
isalpha