<p>一种解决方案是添加重载函数:</p>
<pre><code>void get_async(std::string url, boost::python::object obj)
{
if (PyCallable_Check(obj.ptr()))
get_async(url, static_cast<boost::function<void(int)>>(obj));
}
</code></pre>
<p>然后暴露这个特定的过载:</p>
^{pr2}$
<p>或者,如果你不想用python的东西污染你的主类,那么你可以创建一个包装类。事情看起来也干净多了:</p>
<pre><code>struct http_manager_wrapper : http_manager
{
void get_async(std::string url, boost::python::object obj)
{
if (PyCallable_Check(obj.ptr()))
http_manager::get_async(url, obj);
}
} http_wrapper;
BOOST_PYTHON_MODULE(example)
{
boost::python::class_<http_manager_wrapper>("HttpManager", boost::python::no_init)
.def("get_async", &http_manager_wrapper::get_async);
boost::python::scope().attr("http") = boost::ref(http_wrapper);
}
</code></pre>
<hr/>
<p><strong>更新:</strong>另一个选择是使用python可调用的boost函数转换器。这将解决单例问题,并且不需要更改主类。在</p>
<pre><code>struct http_manager
{
void get_async(std::string url, boost::function<void(int)> on_response)
{
if (on_response)
{
on_response(42);
}
}
} http;
struct BoostFunc_from_Python_Callable
{
BoostFunc_from_Python_Callable()
{
boost::python::converter::registry::push_back(&convertible, &construct, boost::python::type_id< boost::function< void(int) > >());
}
static void* convertible(PyObject* obj_ptr)
{
if (!PyCallable_Check(obj_ptr))
return 0;
return obj_ptr;
}
static void construct(PyObject* obj_ptr, boost::python::converter::rvalue_from_python_stage1_data* data)
{
boost::python::object callable(boost::python::handle<>(boost::python::borrowed(obj_ptr)));
void* storage = ((boost::python::converter::rvalue_from_python_storage< boost::function< void(int) > >*) data)->storage.bytes;
new (storage)boost::function< void(int) >(callable);
data->convertible = storage;
}
};
BOOST_PYTHON_MODULE(example)
{
// Register function converter
BoostFunc_from_Python_Callable();
boost::python::class_<http_manager>("HttpManager", boost::python::no_init)
.def("get_async", &http_manager::get_async);
boost::python::scope().attr("http") = boost::ref(http);
}
</code></pre>