<i id='4SsHb'><tr id='4SsHb'><dt id='4SsHb'><q id='4SsHb'><span id='4SsHb'><b id='4SsHb'><form id='4SsHb'><ins id='4SsHb'></ins><ul id='4SsHb'></ul><sub id='4SsHb'></sub></form><legend id='4SsHb'></legend><bdo id='4SsHb'><pre id='4SsHb'><center id='4SsHb'></center></pre></bdo></b><th id='4SsHb'></th></span></q></dt></tr></i><div id='4SsHb'><tfoot id='4SsHb'></tfoot><dl id='4SsHb'><fieldset id='4SsHb'></fieldset></dl></div>

    <tfoot id='4SsHb'></tfoot>
    1. <legend id='4SsHb'><style id='4SsHb'><dir id='4SsHb'><q id='4SsHb'></q></dir></style></legend>

    2. <small id='4SsHb'></small><noframes id='4SsHb'>

      • <bdo id='4SsHb'></bdo><ul id='4SsHb'></ul>

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

      时间:2023-10-17

      <small id='ecNPa'></small><noframes id='ecNPa'>

      <tfoot id='ecNPa'></tfoot>

          <bdo id='ecNPa'></bdo><ul id='ecNPa'></ul>

            <tbody id='ecNPa'></tbody>
          <legend id='ecNPa'><style id='ecNPa'><dir id='ecNPa'><q id='ecNPa'></q></dir></style></legend>

            • <i id='ecNPa'><tr id='ecNPa'><dt id='ecNPa'><q id='ecNPa'><span id='ecNPa'><b id='ecNPa'><form id='ecNPa'><ins id='ecNPa'></ins><ul id='ecNPa'></ul><sub id='ecNPa'></sub></form><legend id='ecNPa'></legend><bdo id='ecNPa'><pre id='ecNPa'><center id='ecNPa'></center></pre></bdo></b><th id='ecNPa'></th></span></q></dt></tr></i><div id='ecNPa'><tfoot id='ecNPa'></tfoot><dl id='ecNPa'><fieldset id='ecNPa'></fieldset></dl></div>
              • 本文介绍了如何在函数和成员函数上编写包装器,在包装函数之前和之后执行一些代码?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

                问题描述

                我正在尝试编写一些包装类或函数,以允许我在包装函数之前和之后执行一些代码.

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

                这篇关于如何在函数和成员函数上编写包装器,在包装函数之前和之后执行一些代码?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

                上一篇:使用从字符串中提取的参数调用函数 下一篇:如何使用 bind1st 和 bind2nd?

                相关文章

                1. <legend id='AVreo'><style id='AVreo'><dir id='AVreo'><q id='AVreo'></q></dir></style></legend>
                  <tfoot id='AVreo'></tfoot>

                  <small id='AVreo'></small><noframes id='AVreo'>

                2. <i id='AVreo'><tr id='AVreo'><dt id='AVreo'><q id='AVreo'><span id='AVreo'><b id='AVreo'><form id='AVreo'><ins id='AVreo'></ins><ul id='AVreo'></ul><sub id='AVreo'></sub></form><legend id='AVreo'></legend><bdo id='AVreo'><pre id='AVreo'><center id='AVreo'></center></pre></bdo></b><th id='AVreo'></th></span></q></dt></tr></i><div id='AVreo'><tfoot id='AVreo'></tfoot><dl id='AVreo'><fieldset id='AVreo'></fieldset></dl></div>
                  • <bdo id='AVreo'></bdo><ul id='AVreo'></ul>