gpt4 book ai didi

c++ - 如何编写函数和成员函数的包装器,在包装函数之前和之后执行一些代码?

转载 作者:太空狗 更新时间:2023-10-29 20:53:00 25 4
gpt4 key购买 nike

我正在尝试编写一些包装器类或函数,使我能够在包装函数之前和之后执行一些代码。

float foo(int x, float y)
{
return x * y;
}

BOOST_PYTHON_MODULE(test)
{
boost::python::def("foo", <somehow wrap "&foo">);
}

理想情况下,包装器应该是通用的,适用于具有任何签名的函数和成员函数。

更多信息:

我正在寻找一种简单的方法来围绕我昂贵的 C++ 调用释放/重新获取 GIL,而无需像这样手动编写瘦包装器:

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);
}

这种包装器将针对各种功能重复多次,我想找到一个解决方案,让我避免对所有这些功能进行编码。

我已经尝试了一些方法,但我能想到的最好方法是要求用户明确说明返回值和参数的类型,例如:

boost::python::def("foo", &wrap_gil<float, int, float>(&foo_wrapper));

但在我看来,应该可以只将指针传递给函数 (&foo_wrapper),然后让编译器找出类型。

有没有人知道我可以使用的技术或为我指明正确的方向?

干杯!

最佳答案

在这种情况下,您可以编写一个 Functor 类来包装您的函数,然后重载 boost::python::detail::get_signature 以接受您的 Functor!

更新:也添加了对成员函数的支持!

例子:

#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 上:

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)\n')

self.assertEqual(TestWrappedFunctor(69, 1.618), 'func(a=69, b=1.618)')
self.assertEqual(
GetValueAndClearTestStream(),
(
'[Before action...]\n'
'- In func(a=69, b=1.618)\n'
'[After action...]\n'
),
)

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()
'''),
)

关于c++ - 如何编写函数和成员函数的包装器,在包装函数之前和之后执行一些代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2135457/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com