可组合的C ++函数装饰器 [英] Composable C++ Function Decorators

查看:133
本文介绍了可组合的C ++函数装饰器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Python具有函数装饰器的非常有用的功能,而且,允许合成。例如,如果编写函数 foo ,则可以声明希望 foo 已记忆,而且重试多次(如果发生高速缓存未命中,其中 foo 也会引发异常),方法: / p>

Python has a very useful feature of function decorators, which, moreover, allows composition. For example, if write a function foo, then you can state that you would like foo to be memoized, but also retried more than a single time in case of a cache miss in which foo also raises an exception, by:

@lru_cache
@retry
def foo(...):

装饰器可组合性允许分别开发 foo 之类的函数和各个函数装饰器,然后根据需要混合它们。

Decorator composability allows developing functions like foo and individual function decorators independently, and then mixing them as needed. It would be nice if we could do so in C++ as well (to the extent possible).

虽然我们在C ++中也可以这样做(如果可能),这会很好。虽然StackOverflow上有几个关于函数装饰器的问题,但它们似乎都由于对修饰函数的签名有严格的假设,因此会生成不可组合的函数。例如,考虑对此问题的出色投票。装饰形式为

While there are several questions on StackOverflow regarding function decorators, they all seem to generate non-composable ones, due to rigid assumptions on the signature of the decorated function. E.g., consider the excellent top-voted answer to this question. The decoration is of the form

template <typename R, typename... Args>
std::function<R (Args...)> memo(R (*fn)(Args...)) {

因此,它不能应用于自身的结果(对于特定的装饰器使用记忆)。

Consequently, it cannot be applied to the result of itself (admittedly not much of an issue for the specific decorator use of memoization).

那么如何编写可组合的函数修饰符?

How can we write composable function decorators, then?

推荐答案

创建可组合函数修饰符的另一种方法是使用一组 mixin classes。

遵循一个最小的有效示例:

Another way to create composable function decorators is by using a set of mixin classes.
It follows a minimal, working example:

#include<iostream>
#include<functional>
#include<utility>
#include<type_traits>

template<class T>
struct LoggerDecoratorA: public T {
    template<class U>
    LoggerDecoratorA(const U &u): T{u} { }

    template<typename... Args>
    auto operator()(Args&&... args) const ->
        typename std::enable_if<
            not std::is_same<
                typename std::result_of<T(Args...)>::type,
                void
            >::value,
        typename std::result_of<T(Args...)>::type>::type
    {
        using namespace std;
        cout << "> logger A" << endl;
        auto ret = T::operator()(std::forward<Args>(args)...);
        cout << "< logger A" << endl;
        return ret;
    }

    template<typename... Args>
    auto operator()(Args&&... args) const ->
        typename std::enable_if<
            std::is_same<
                typename std::result_of<T(Args...)>::type,
                void
            >::value,
        typename std::result_of<T(Args...)>::type>::type
    {
        using namespace std;
        cout << "> logger A" << endl;
        T::operator()(std::forward<Args>(args)...);
        cout << "< logger A" << endl;
    }
};

template<class T>
struct LoggerDecoratorB: public T {
    template<class U>
    LoggerDecoratorB(const U &u): T{u} { }

    template<typename... Args>
    auto operator()(Args&&... args) const ->
        typename std::enable_if<
            not std::is_same<
                typename std::result_of<T(Args...)>::type,
                void
            >::value,
        typename std::result_of<T(Args...)>::type>::type
    {
        using namespace std;
        cout << "> logger B" << endl;
        auto ret = T::operator()(std::forward<Args>(args)...);
        cout << "< logger B" << endl;
        return ret;
    }

    template<typename... Args>
    auto operator()(Args&&... args) const ->
        typename std::enable_if<
            std::is_same<
                typename std::result_of<T(Args...)>::type,
                void
            >::value,
        typename std::result_of<T(Args...)>::type>::type
    {
        using namespace std;
        cout << "> logger B" << endl;
        T::operator()(std::forward<Args>(args)...);
        cout << "< logger B" << endl;
    }
};

int main() {
    std::function<int()> fn = [](){
        using namespace std;
        cout << 42 << endl;
        return 42;
    };

    std::function<void()> vFn = [](){
        using namespace std;
        cout << "void" << endl;
    };

    using namespace std;

    decltype(fn) aFn =
        LoggerDecoratorA<decltype(fn)>(fn);
    aFn();

    cout << "---" << endl;

    decltype(vFn) bVFn =
        LoggerDecoratorB<decltype(vFn)>(vFn);
    bVFn();

    cout << "---" << endl;

    decltype(fn) abFn =
        LoggerDecoratorA<LoggerDecoratorB<decltype(fn)>>(fn);
    abFn();

    cout << "---" << endl;

    decltype(fn) baFn =
        LoggerDecoratorB<LoggerDecoratorA<decltype(fn)>>(fn);
    baFn();
}

我不确定您提到的问题实际解决了什么,但是随时要求更改,如果可能,我会尝试进行更新。

I'm not sure what of the problems you mentioned it actually solves, but feel free to ask for changes and I'll try to update it if possible.

这篇关于可组合的C ++函数装饰器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆