How to write a wrapper over functions and member functions that executes some code before and after the wrapped function?(如何在函数和成员函数上编写包装器,在包装函数之前和之后执行一些代码?)
问题描述
我正在尝试编写一些包装类或函数,以允许我在包装函数之前和之后执行一些代码.
I'm trying to write some wrapper class or function that allows me to execute some code before and after the wrapped function.
float foo(int x, float y)
{
return x * y;
}
BOOST_PYTHON_MODULE(test)
{
boost::python::def("foo", <somehow wrap "&foo">);
}
理想情况下,包装器应该是通用的,适用于具有任何签名的函数和成员函数.
Ideally, the wrapper should be generic, working for functions and member functions alike, with any signature.
更多信息:
我正在寻找一种简单的方法来释放/重新获取我昂贵的 C++ 调用周围的 GIL,而无需像这样手动编写瘦包装器:
I'm looking for a simple way to release/re-acquire the GIL around my expensive C++ calls without having to manually write thin wrappers like this:
float foo_wrapper(int x, float y)
{
Py_BEGIN_ALLOW_THREADS
int result = foo(x, y);
Py_END_ALLOW_THREADS
return result;
}
BOOST_PYTHON_MODULE(test)
{
boost::python::def("foo", &foo_wrapper);
}
这种包装器会为各种函数重复多次,我想找到一种解决方案,让我避免对所有函数进行编码.
This kind of wrapper will be repeated several times for all kinds of functions, and I would like to find a solution that would allow me to avoid coding all of them.
我尝试了一些方法,但最好的方法是要求用户明确说明返回值和参数的类型,例如:
I have tried some approaches, but the best I could come with required the user to explicitly state the types of return values and parameters, like:
boost::python::def("foo", &wrap_gil<float, int, float>(&foo_wrapper));
但在我看来,应该可以只将指针传递给函数 (&foo_wrapper) 并让编译器找出类型.
But it seems to me it should be possible to just pass the pointer to the function (&foo_wrapper) and let the compiler figure out the types.
有没有人知道我可以使用的技术或为我指明正确的方向?
Does anyone know a technique I could use or point me in the right direction?
干杯!
推荐答案
在这种情况下,您可以编写一个 Functor 类来包装您的函数,然后重载 boost::python::detail::get_signature 以接受您的 Functor!
In this case, you can write a Functor class that wraps over your function, and then overload boost::python::detail::get_signature to accept your Functor!
更新:也增加了对成员函数的支持!
UPDATE: Added support for member functions too!
示例:
#include <boost/shared_ptr.hpp>
#include <boost/python.hpp>
#include <boost/python/signature.hpp>
#include <boost/mpl/vector.hpp>
#include <iostream>
#include <string>
#include <sstream>
static boost::shared_ptr<std::ostringstream> test_stream_data;
std::ostringstream& test_stream()
{
if (!test_stream_data) {
test_stream_data.reset(new std::ostringstream);
}
return *test_stream_data;
}
std::string get_value_and_clear_test_stream()
{
std::string result;
if (test_stream_data) {
result = test_stream_data->str();
}
test_stream_data.reset(new std::ostringstream);
return result;
}
std::string func(int a, double b)
{
std::ostringstream oss;
oss << "func(a=" << a << ", b=" << b << ")";
std::string result = oss.str();
test_stream() << "- In " << result << std::endl;
return result;
}
class MyClass
{
public:
MyClass(std::string p_name)
: m_name(p_name)
{
test_stream() << "- In MyClass::MyClass(p_name="" << p_name << "")" << std::endl;
}
MyClass(MyClass const& p_another)
: m_name(p_another.m_name)
{
test_stream()
<< "- In MyClass::MyClass(p_another=MyClass(""
<< p_another.m_name << ""))" << std::endl;
}
~MyClass()
{
test_stream() << "- In MyClass("" << this->m_name << "")::~MyClass()" << std::endl;
}
boost::shared_ptr<MyClass> clone_and_change(std::string p_new_name)
{
test_stream()
<< "- In MyClass("" << this->m_name << "").clone_and_change(p_new_name=""
<< p_new_name << "")" << std::endl;
boost::shared_ptr<MyClass> result(new MyClass(*this));
result->m_name = p_new_name;
return result;
}
std::string get_name()
{
test_stream() << "- In MyClass("" << this->m_name << "").get_name()" << std::endl;
return this->m_name;
}
std::string m_name;
};
struct ScopePreAndPostActions
{
ScopePreAndPostActions()
{
test_stream() << "[Before action...]" << std::endl;
}
~ScopePreAndPostActions()
{
test_stream() << "[After action...]" << std::endl;
}
};
template <class FuncType_>
struct FuncWrapper;
// You can code-generate specializations for other arities...
template <class R_, class A0_, class A1_>
struct FuncWrapper<R_ (A0_, A1_)>
{
typedef R_ (*func_type)(A0_, A1_);
typedef typename boost::add_const<typename boost::add_reference<typename A0_>::type>::type AC0_;
typedef typename boost::add_const<typename boost::add_reference<typename A1_>::type>::type AC1_;
func_type m_wrapped_func;
FuncWrapper(func_type p_wrapped_func)
: m_wrapped_func(p_wrapped_func)
{
}
R_ operator()(AC0_ p0, AC1_ p1)
{
ScopePreAndPostActions actions_guard;
return this->m_wrapped_func(p0, p1);
}
};
template <
class R_,
class C_,
class A0_=void,
class A1_=void,
class A2_=void
// ...
>
struct MemberFuncWrapper;
template <class R_, class C_, class A0_>
struct MemberFuncWrapper<R_, C_, A0_>
{
typedef R_ (C_::*member_func_type)(A0_);
typedef typename boost::add_const<typename boost::add_reference<typename A0_>::type>::type AC0_;
member_func_type m_wrapped_method;
MemberFuncWrapper(member_func_type p_wrapped_method)
: m_wrapped_method(p_wrapped_method)
{
}
R_ operator()(C_* p_self, AC0_ p0)
{
ScopePreAndPostActions actions_guard;
return (p_self->*(this->m_wrapped_method))(p0);
return R_();
}
};
namespace boost { namespace python { namespace detail {
// You can code-generate specializations for other arities...
template <class R_, class P0_, class P1_>
inline boost::mpl::vector<R_, P0_, P1_>
get_signature(FuncWrapper<R_ (P0_, P1_)>, void* = 0)
{
return boost::mpl::vector<R_, P0_, P1_>();
}
template <class R_, class C_, class P0_>
inline boost::mpl::vector<R_, C_*, P0_>
get_signature(MemberFuncWrapper<R_, C_, P0_>, void* = 0)
{
return boost::mpl::vector<R_, C_*, P0_>();
}
} } }
// -------------------------------------------------------------------
template <class FuncPtr_>
void make_wrapper(FuncPtr_);
// You can code-generate specializations for other arities...
template <class R_, class A0_, class A1_>
FuncWrapper<R_ (A0_, A1_)> make_wrapper(R_ (*p_wrapped_func)(A0_, A1_))
{
return FuncWrapper<R_ (A0_, A1_)>(p_wrapped_func);
}
template <class R_, class C_, class A0_>
MemberFuncWrapper<R_, C_, A0_> make_wrapper(R_ (C_::*p_wrapped_method)(A0_))
{
return MemberFuncWrapper<R_, C_, A0_>(p_wrapped_method);
}
template <class R_, class C_, class A0_, class A1_>
MemberFuncWrapper<R_, C_, A0_, A1_> make_wrapper(R_ (C_::*p_wrapped_method)(A0_, A1_))
{
return MemberFuncWrapper<R_, C_, A0_, A1_>(p_wrapped_method);
}
using namespace boost::python;
void RegisterTestWrapper()
{
def("GetValueAndClearTestStream", &get_value_and_clear_test_stream);
def("TestFunc", &func);
def(
"TestWrappedFunctor",
make_wrapper(&func)
);
{
class_< MyClass, shared_ptr<MyClass>, boost::noncopyable > c("MyClass", init<std::string>());
c.def("CloneAndChange", &MyClass::clone_and_change);
c.def("GetName", &MyClass::get_name);
c.def("WrappedCloneAndChange", make_wrapper(&MyClass::clone_and_change));
}
}
在 python 上:
And on python:
import unittest
from _test_wrapper import GetValueAndClearTestStream, TestFunc, TestWrappedFunctor, MyClass
class Test(unittest.TestCase):
def setUp(self):
GetValueAndClearTestStream()
def testWrapper(self):
self.assertEqual(TestFunc(69, 1.618), 'func(a=69, b=1.618)')
self.assertEqual(GetValueAndClearTestStream(), '- In func(a=69, b=1.618)
')
self.assertEqual(TestWrappedFunctor(69, 1.618), 'func(a=69, b=1.618)')
self.assertEqual(
GetValueAndClearTestStream(),
(
'[Before action...]
'
'- In func(a=69, b=1.618)
'
'[After action...]
'
),
)
def testWrappedMemberFunction(self):
from textwrap import dedent
x = MyClass("xx")
y = x.WrappedCloneAndChange("yy")
z = y.WrappedCloneAndChange("zz")
self.assertEqual(x.GetName(), "xx")
self.assertEqual(y.GetName(), "yy")
self.assertEqual(z.GetName(), "zz")
self.assertEqual(
GetValueAndClearTestStream(),
dedent('''
- In MyClass::MyClass(p_name="xx")
[Before action...]
- In MyClass("xx").clone_and_change(p_new_name="yy")
- In MyClass::MyClass(p_another=MyClass("xx"))
[After action...]
[Before action...]
- In MyClass("yy").clone_and_change(p_new_name="zz")
- In MyClass::MyClass(p_another=MyClass("yy"))
[After action...]
- In MyClass("xx").get_name()
- In MyClass("yy").get_name()
- In MyClass("zz").get_name()
'''),
)
这篇关于如何在函数和成员函数上编写包装器,在包装函数之前和之后执行一些代码?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:如何在函数和成员函数上编写包装器,在包装函数之前和之后执行一些代码?
基础教程推荐
- 如何使图像调整大小以在 Qt 中缩放? 2021-01-01
- 管理共享内存应该分配多少内存?(助推) 2022-12-07
- 从 std::cin 读取密码 2021-01-01
- 如何“在 Finder 中显示"或“在资源管理器中显 2021-01-01
- 为 C/C++ 中的项目的 makefile 生成依赖项 2022-01-01
- 为什么语句不能出现在命名空间范围内? 2021-01-01
- 如何在不破坏 vtbl 的情况下做相当于 memset(this, ...) 的操作? 2022-01-01
- 使用从字符串中提取的参数调用函数 2022-01-01
- Windows Media Foundation 录制音频 2021-01-01
- 在 C++ 中循环遍历所有 Lua 全局变量 2021-01-01