我正在将 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)
In C++ 中的函数挂钩, 我们发现这个答案它包装了实例,并将调用计时函数的负担置于调用者身上,这意味着我们无法在整个代码库中获取性能数据(一开始更新很烦人,而且以后很容易忘记)。相似地,这个答案 to 在 C++ 中以优雅的方式计时需要更改调用站点。这个另一个答案这个问题提供了一种包装任意代码块的方法,这在理论上意味着我们可以缩进我们想要计时的函数的整个主体并将其嵌套在一个范围内。这是我发现的最接近我想要的,但是相当丑陋,相当具有侵入性,而且我不确定对性能的影响。
由于这是一个库,我们可以修改我们想要计时的函数的源代码;事实上,正如我所愿,这是更好的选择every对该函数的调用要计时。大多数讨论似乎都集中在开发中的临时分析上,而我正在尝试构建一个在生产环境中始终处于活动状态的系统。
尽管 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);
}
Live on Coliru
当然,在装饰器内部,您可以添加任何您想要的内容(包括计时等),上面只是一个最小的示例。
如果它看起来太令人畏惧,你可以忽略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);
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)