[C++-sig] Making boost::optional<T> passable to/from Python
John Wiegley
jwiegley at gmail.com
Fri May 4 15:39:13 CEST 2007
The following code will make it possible to use boost::optional<T>
very easily with Boost.Python. For every time you expect to be used
optionally, you must call the following during module initialization:
python_optional<some_type_t>();
You can now accept and return boost::optional<some_type_t>(). In
both directions, None will reflect an uninitialized value, while data
of the correct type represents an initialized value. Needless to
say, valid conversions must already exist for some_type_t, otherwise
an error is generated claiming that the optional type cannot be
converted.
John Wiegley
template <typename T, typename TfromPy>
struct object_from_python
{
object_from_python() {
boost::python::converter::registry::push_back
(&TfromPy::convertible, &TfromPy::construct,
boost::python::type_id<T>());
}
};
template <typename T, typename TtoPy, typename TfromPy>
struct register_python_conversion
{
register_python_conversion() {
boost::python::to_python_converter<T, TtoPy>();
object_from_python<T, TfromPy>();
}
};
template <typename T>
struct python_optional : public boost::noncopyable
{
struct optional_to_python
{
static PyObject * convert(const boost::optional<T>& value)
{
return (value ? boost::python::to_python_value<T>()(*value) :
boost::python::detail::none());
}
};
struct optional_from_python
{
static void * convertible(PyObject * source)
{
using namespace boost::python::converter;
if (source == Py_None)
return source;
const registration& converters(registered<T>::converters);
if (implicit_rvalue_convertible_from_python(source,
converters)) {
rvalue_from_python_stage1_data data =
rvalue_from_python_stage1(source, converters);
return rvalue_from_python_stage2(source, data, converters);
}
return NULL;
}
static void construct(PyObject * source,
boost::python::converter::rvalue_from_python_stage1_data * data)
{
using namespace boost::python::converter;
void * const storage = ((rvalue_from_python_storage<T> *)
data)->storage.bytes;
if (data->convertible == source) // == None
new (storage) boost::optional<T>(); // A Boost uninitialized value
else
new (storage) boost::optional<T>(*static_cast<T *>(data->convertible));
data->convertible = storage;
}
};
explicit python_optional() {
register_python_conversion<boost::optional<T>,
optional_to_python, optional_from_python>();
}
};
More information about the Cplusplus-sig
mailing list