Python 类 C++ 装饰器
Python-like C++ decorators
有没有像 python 风格那样在 C++ 中修饰函数或方法的方法?
@decorator
def decorated(self, *args, **kwargs):
pass
使用宏举例:
DECORATE(decorator_method)
int decorated(int a, float b = 0)
{
return 0;
}
或
DECORATOR_MACRO
void decorated(mytype& a, mytype2* b)
{
}
可能吗?
您可以使用标记粘贴预处理运算符## 获得此类的一些有限功能。参见 https://gcc.gnu.org/onlinedocs/cpp/Concatenation.html。困难在于,在 C 中,每个函数名称都必须在 link 时定义,因此函数不是可以像 Python 那样转换的对象。所以在 Python 中,装饰器是有用的和好的风格,但在 C 中,如果有的话,应该谨慎使用这样的技巧。
std::function
为我提出的解决方案提供了大部分构建块。
这是我提出的解决方案。
#include <iostream>
#include <functional>
//-------------------------------
// BEGIN decorator implementation
//-------------------------------
template <class> struct Decorator;
template <class R, class... Args>
struct Decorator<R(Args ...)>
{
Decorator(std::function<R(Args ...)> f) : f_(f) {}
R operator()(Args ... args)
{
std::cout << "Calling the decorated function.\n";
return f_(args...);
}
std::function<R(Args ...)> f_;
};
template<class R, class... Args>
Decorator<R(Args...)> makeDecorator(R (*f)(Args ...))
{
return Decorator<R(Args...)>(std::function<R(Args...)>(f));
}
//-------------------------------
// END decorator implementation
//-------------------------------
//-------------------------------
// Sample functions to decorate.
//-------------------------------
// Proposed solution doesn't work with default values.
// int decorated1(int a, float b = 0)
int decorated1(int a, float b)
{
std::cout << "a = " << a << ", b = " << b << std::endl;
return 0;
}
void decorated2(int a)
{
std::cout << "a = " << a << std::endl;
}
int main()
{
auto method1 = makeDecorator(decorated1);
method1(10, 30.3);
auto method2 = makeDecorator(decorated2);
method2(10);
}
输出:
Calling the decorated function.
a = 10, b = 30.3
Calling the decorated function.
a = 10
PS
Decorator
提供了一个地方,您可以在其中添加除进行函数调用之外的功能。如果你想简单地传递到 std::function
,你可以使用:
template<class R, class... Args >
std::function<R(Args...)> makeDecorator(R (*f)(Args ...))
{
return std::function<R(Args...)>(f);
}
这是我的尝试。在 C++14 下工作(通用 lambda 和 return 类型推导)。
#include <iostream>
#include <functional>
/* Decorator function example,
returns negative (! operator) of given function
*/
template <typename T>
auto reverse_func(T func)
{
auto r_func =
[=](auto ...args)
{
return !func(args...);
};
return r_func;
}
/* Decorator function example,
prints result of given function before it's returned
*/
template <typename T>
auto print_result_func(T func)
{
auto r_func =
[=](auto ...args)
{
auto result = func(args...);
std::cout << "Result: " << result << std::endl;
return result;
};
return r_func;
}
/* Function to be decorated example,
checks whether two given arguments are equal
*/
bool cmp(int x, int y)
{
return x == y;
}
/* Decorator macro */
#define DECORATE(function, decorator) \
decorator<decltype(function)>(function)
int main()
{
auto reversed = DECORATE(cmp, reverse_func);
auto print_normal = DECORATE(cmp, print_result_func);
auto print_reversed = DECORATE(reversed, print_result_func);
auto print_double_normal = DECORATE(print_normal, print_result_func);
auto print_double_reversed = DECORATE(print_reversed, print_result_func);
std::cout << cmp(1,2) << reversed(1,2) << std::endl;
print_double_normal(1,2);
print_reversed(1,2);
print_double_reversed(1,2);
}
上面所有的答案都很复杂并且使用了库。
我这里的答案是迄今为止最简单的,不需要任何库头文件。
// "DECORATOR.h"
#pragma once
#ifndef DECORATOR_H
#define DECORATOR_H
template<typename T>
class deco
{
T* m_func;
public:
explicit deco(T func);
template<typename ...args>
auto operator()(args... Args);
}
#endif // DECORATOR_H
现在在实现文件中执行以下操作
// "DECORATOR.cpp"
template<typename T>
inline deco<T>::deco(T func)
:m_func(func)
{
};
// implementing the function call operator
template <typename T>
template <typename ...args>
auto deco<T>::operator()(args ...Args)
{
//Do some stuff defore the decorated function call
// ....
// Call the decorated function.
auto rv = m_func(Args...);
//Do some stuff after the function call
// ....
return rv;
}
故事结束。
现在这是在您的代码中使用它的方法。
// "main.cpp"
#include "DECORATOR.h"
#include <stdio.h> // just for printf()
// functions to decorate
int add(int a, int b)
{
return a+b;
};
int sub(int a, int b)
{
return a-b;
};
// Main function
int main()
{
// decorate the functions "add", "sub"
deco<decltype(add)> add_Deco(add);
deco<decltype(sub)> sub_Deco(sub);
// call your decorated functions
printf("result of decorated Add =%d\n", add_Deco(5,2));
printf("result of decorated Sub =%d\n", sub_Deco(4,3));
return 0;
}
伙计们,就是这样!
优点:
CLASS"deco"只有一个数据成员=>内存占用小
operator() 接受任意数量的参数,因此您可以修饰任何函数,而不管其参数数量如何。
简单实现=>简单调试和测试。
缺点:
- none已知!
github 上有一个项目,它是关于如何为 C++14 及更高版本实现此行为的简短教程。这是一个非常灵活的设计,也可以装饰非静态函数。作者也没有使用任何复杂的东西:
https://github.com/TheMaverickProgrammer/C-Python-like-Decorators
有没有像 python 风格那样在 C++ 中修饰函数或方法的方法?
@decorator
def decorated(self, *args, **kwargs):
pass
使用宏举例:
DECORATE(decorator_method)
int decorated(int a, float b = 0)
{
return 0;
}
或
DECORATOR_MACRO
void decorated(mytype& a, mytype2* b)
{
}
可能吗?
您可以使用标记粘贴预处理运算符## 获得此类的一些有限功能。参见 https://gcc.gnu.org/onlinedocs/cpp/Concatenation.html。困难在于,在 C 中,每个函数名称都必须在 link 时定义,因此函数不是可以像 Python 那样转换的对象。所以在 Python 中,装饰器是有用的和好的风格,但在 C 中,如果有的话,应该谨慎使用这样的技巧。
std::function
为我提出的解决方案提供了大部分构建块。
这是我提出的解决方案。
#include <iostream>
#include <functional>
//-------------------------------
// BEGIN decorator implementation
//-------------------------------
template <class> struct Decorator;
template <class R, class... Args>
struct Decorator<R(Args ...)>
{
Decorator(std::function<R(Args ...)> f) : f_(f) {}
R operator()(Args ... args)
{
std::cout << "Calling the decorated function.\n";
return f_(args...);
}
std::function<R(Args ...)> f_;
};
template<class R, class... Args>
Decorator<R(Args...)> makeDecorator(R (*f)(Args ...))
{
return Decorator<R(Args...)>(std::function<R(Args...)>(f));
}
//-------------------------------
// END decorator implementation
//-------------------------------
//-------------------------------
// Sample functions to decorate.
//-------------------------------
// Proposed solution doesn't work with default values.
// int decorated1(int a, float b = 0)
int decorated1(int a, float b)
{
std::cout << "a = " << a << ", b = " << b << std::endl;
return 0;
}
void decorated2(int a)
{
std::cout << "a = " << a << std::endl;
}
int main()
{
auto method1 = makeDecorator(decorated1);
method1(10, 30.3);
auto method2 = makeDecorator(decorated2);
method2(10);
}
输出:
Calling the decorated function.
a = 10, b = 30.3
Calling the decorated function.
a = 10
PS
Decorator
提供了一个地方,您可以在其中添加除进行函数调用之外的功能。如果你想简单地传递到 std::function
,你可以使用:
template<class R, class... Args >
std::function<R(Args...)> makeDecorator(R (*f)(Args ...))
{
return std::function<R(Args...)>(f);
}
这是我的尝试。在 C++14 下工作(通用 lambda 和 return 类型推导)。
#include <iostream>
#include <functional>
/* Decorator function example,
returns negative (! operator) of given function
*/
template <typename T>
auto reverse_func(T func)
{
auto r_func =
[=](auto ...args)
{
return !func(args...);
};
return r_func;
}
/* Decorator function example,
prints result of given function before it's returned
*/
template <typename T>
auto print_result_func(T func)
{
auto r_func =
[=](auto ...args)
{
auto result = func(args...);
std::cout << "Result: " << result << std::endl;
return result;
};
return r_func;
}
/* Function to be decorated example,
checks whether two given arguments are equal
*/
bool cmp(int x, int y)
{
return x == y;
}
/* Decorator macro */
#define DECORATE(function, decorator) \
decorator<decltype(function)>(function)
int main()
{
auto reversed = DECORATE(cmp, reverse_func);
auto print_normal = DECORATE(cmp, print_result_func);
auto print_reversed = DECORATE(reversed, print_result_func);
auto print_double_normal = DECORATE(print_normal, print_result_func);
auto print_double_reversed = DECORATE(print_reversed, print_result_func);
std::cout << cmp(1,2) << reversed(1,2) << std::endl;
print_double_normal(1,2);
print_reversed(1,2);
print_double_reversed(1,2);
}
上面所有的答案都很复杂并且使用了库。 我这里的答案是迄今为止最简单的,不需要任何库头文件。
// "DECORATOR.h"
#pragma once
#ifndef DECORATOR_H
#define DECORATOR_H
template<typename T>
class deco
{
T* m_func;
public:
explicit deco(T func);
template<typename ...args>
auto operator()(args... Args);
}
#endif // DECORATOR_H
现在在实现文件中执行以下操作
// "DECORATOR.cpp"
template<typename T>
inline deco<T>::deco(T func)
:m_func(func)
{
};
// implementing the function call operator
template <typename T>
template <typename ...args>
auto deco<T>::operator()(args ...Args)
{
//Do some stuff defore the decorated function call
// ....
// Call the decorated function.
auto rv = m_func(Args...);
//Do some stuff after the function call
// ....
return rv;
}
故事结束。 现在这是在您的代码中使用它的方法。
// "main.cpp"
#include "DECORATOR.h"
#include <stdio.h> // just for printf()
// functions to decorate
int add(int a, int b)
{
return a+b;
};
int sub(int a, int b)
{
return a-b;
};
// Main function
int main()
{
// decorate the functions "add", "sub"
deco<decltype(add)> add_Deco(add);
deco<decltype(sub)> sub_Deco(sub);
// call your decorated functions
printf("result of decorated Add =%d\n", add_Deco(5,2));
printf("result of decorated Sub =%d\n", sub_Deco(4,3));
return 0;
}
伙计们,就是这样!
优点:
CLASS"deco"只有一个数据成员=>内存占用小
operator() 接受任意数量的参数,因此您可以修饰任何函数,而不管其参数数量如何。
简单实现=>简单调试和测试。
缺点:
- none已知!
github 上有一个项目,它是关于如何为 C++14 及更高版本实现此行为的简短教程。这是一个非常灵活的设计,也可以装饰非静态函数。作者也没有使用任何复杂的东西:
https://github.com/TheMaverickProgrammer/C-Python-like-Decorators