我正在将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)
在C ++中的函数挂钩中,我们找到了这个包装实例的答案,并将调用计时函数的负担放在了调用方上,这意味着我们不会在整个代码库中获得性能数据(首先要进行更新很烦人,而且很容易以后忘记)。类似地,在c ++中以一种优雅的方式对Timing的答案需要更改调用站点。这个问题的另一个答案提供了一种包装任意代码块的方法,从理论上讲,这意味着我们可以缩进要计时的函数的整个主体,并将其嵌套在范围内。这是我找到的最接近我想要的东西,但是它很丑陋,相当令人讨厌,而且我不确定性能是否会受到影响。
因为它打算用作库,所以我们可以修改想要计时的函数的来源;实际上,这是可取的,因为我希望该函数的每次调用都可以定时。大多数讨论似乎都集中在开发中的临时概要分析上,而我正在尝试构建一个在生产环境中始终有效的系统。
尽管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-jumbostd::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);
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句