6

So, I have a simple event library, written in C++ and using the Boost libraries. I wanted to expose said library to Python, so naturally I turned to Boost::Python. I got the code to compile, eventually, but now I'm faced with quite the problem: my library uses higher-order programming techniques. For example, the library is made up of three main classes: an event class, an event manager class, and an event listener class. The event listener class poses a problem. Code:

    class listener{
        public:
            listener(){}
            void alert(cham::event::event e){
                if (responses[e.getName()])
                    responses[e.getName()](e.getData());
            }
            void setResponse(std::string n, boost::function<void (std::string d)> c){responses.insert(make_pair(n, c));}
            void setManager(_manager<listener> *m){manager = m;}
        private:
            std::map<std::string, boost::function<void (std::string d)> > responses;
            _manager<listener> *manager;

As you can see, the function setResponse is the problem. It requires a function to be passed to it, and, unfortunately, Boost::Python does not apply it's converter magic in this situation. When called like the following:

>>> import chameleon
>>> man = chameleon.manager()
>>> lis = chameleon.listener()
>>> def oup(s):
...  print s
... 
>>> lis.setResponse("event", oup)

it gives this error:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
Boost.Python.ArgumentError: Python argument types in
    listener.setResponse(listener, str, function)
did not match C++ signature:
    setResponse(cham::event::listener {lvalue}, std::string, boost::function<void ()(std::string)>)

So, my question is, how could I fix this? It would have to either use overloading or a wrapper, as I would like the library to remain callable by C++.

1
  • +1 because I think Boost::Python is a very cool idea. Commented Feb 27, 2012 at 21:58

1 Answer 1

2

You will need a wrapper around setResponse, which takes a boost::python::object instead of a function. It should store this bp::object in a known location (probably a member variable of a listener subclass).

Then pass a different c++ function to the base setResponse, that will know how to lookup and call the function in the bp::object. If events are to be called on a different thread, you will also need to ensure proper handling of python's Global Interpreter Lock, as discussed here: boost.python not supporting parallelism?.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks! I fixed it before I read this, using pretty much the same methodology. I just added an additional template argument to listener, passed in python::object instead of boost::function, and named it python_listener with a typedef. Works like a charm.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.