Программирование высшего порядка с использованием Boost::Python

Итак, у меня есть простая библиотека событий, написанная на C++ и использующая библиотеки Boost. Я хотел открыть указанную библиотеку для Python, поэтому, естественно, я обратился к Boost::Python. В конце концов, я получил код для компиляции, но теперь я столкнулся с серьезной проблемой: моя библиотека использует методы программирования более высокого порядка. Например, библиотека состоит из трех основных классов: класса событий, класса диспетчера событий и класса прослушивателя событий. Класс прослушивателя событий создает проблему. Код:

    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;

Как видите, проблема в функции setResponse. Для этого требуется передать ему функцию, и, к сожалению, Boost::Python не применяет свою магию преобразователя в этой ситуации. При вызове следующим образом:

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

это дает эту ошибку:

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

Итак, мой вопрос: как я могу это исправить? Придется либо использовать перегрузку, либо оболочку, так как я хотел бы, чтобы библиотека оставалась доступной для вызова C++.


person Samuel Breese    schedule 27.02.2012    source источник
comment
+1, потому что я думаю, что Boost::Python - очень крутая идея.   -  person zmbq    schedule 28.02.2012


Ответы (1)


Вам понадобится оболочка вокруг setResponse, которая принимает boost::python::object вместо функции. Он должен хранить это bp::object в известном месте (возможно, в переменной-члене подкласса listener).

Затем передайте другую функцию C++ в базу setResponse, которая будет знать, как искать и вызывать функцию в bp::object. Если события должны вызываться в другом потоке, вам также необходимо обеспечить правильную обработку глобальной блокировки интерпретатора Python, как описано здесь: boost.python не поддерживает параллелизм?.

person Matthew Scouten    schedule 28.02.2012
comment
Спасибо! Я исправил это до того, как прочитал это, используя почти ту же методологию. Я просто добавил в слушатель дополнительный аргумент шаблона, переданный в python::object вместо boost::function, и назвал его python_listener с typedef. Работает как шарм. - person Samuel Breese; 03.03.2012