【问题标题】:What's the equivalent of Python function decorators in C++?C++ 中 Python 函数装饰器的等价物是什么?
【发布时间】:2016-11-03 02:01:55
【问题描述】:

我正在将 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 answerTiming in an elegant way in c++ 需要更改呼叫站点。该问题的This other answer 提供了一种包装任意代码块的方法,这在理论上意味着我们可以缩进我们想要计时的函数的整个主体并将其嵌套在范围内。这是我发现的最接近我想要的东西,但是非常丑陋,相当侵入性,而且我不确定性能影响。

由于这是用作库,我们可以修改我们想要计时的函数的来源;事实上,这是更可取的,因为我希望对该函数的 每个 调用都进行计时。大多数讨论似乎都集中在开发中的临时分析上,而我正在尝试构建一个在生产环境中始终处于活动状态的系统。

【问题讨论】:

  • C++ 没有与此 python 功能等效的功能。

标签: c++


【解决方案1】:

尽管 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

当然,你可以在装饰器中添加任何你想要的东西(包括时间等),上面只是一个最小的例子。 如果它看起来太令人生畏,您可以忽略 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);
}

【讨论】:

    【解决方案2】:

    C++ 没有 Pythonic 装饰器,但它具有确定性破坏。要对函数计时,请创建一个在构造时捕获时间戳并在销毁时报告的类。然后在函数的第一行声明一个实例:

    class Timed
    {
    //...
    }
    
    void foo()
    {
        Timed t_;
    
        //Do the rest of work
    }
    

    【讨论】:

    • 这将产生稍微不同的时序 - 复制参数和返回值所需的时间将不包括在内(尽管在大多数情况下,与时序代码本身引入的开销相比,它可以忽略不计)。
    猜你喜欢
    • 2010-11-28
    • 1970-01-01
    • 1970-01-01
    • 2019-04-02
    • 2011-01-30
    • 1970-01-01
    • 2014-05-17
    • 2021-02-14
    相关资源
    最近更新 更多