How to write a wrapper over functions and member functions that executes some code before and after the wrapped function?

前端 未结 2 1502
难免孤独
难免孤独 2020-12-09 12:56

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)
{
           


        
相关标签:
2条回答
  • 2020-12-09 13:25

    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!

    Example:

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

    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)\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()
            '''),
        )
    
    0 讨论(0)
  • 2020-12-09 13:49

    Have you looked at the function wrapping technique described by Stroustrup in his "Wrapping C++ Member Function Calls" paper? There's also a SO response here that demonstrates how to implement it in a concise manner. Basically you'd implement a template that overloads operator->(). Within that operator's implementation you'd construct a temporary object before your actual function call. The temporary object's constructor and destructor take care of invoking your "pre-" and "post-" code before and after your actual function call, respectively.

    0 讨论(0)
提交回复
热议问题