...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
copy_const_reference
is a model of ResultConverterGenerator
which can be used to wrap C++ functions returning a reference-to-const
type such that the referenced value is copied into a new Python object.
namespace boost { namespace python { struct copy_const_reference { template <class T> struct apply; }; }}
template <class T> struct apply
T
is U const&
for some U
.
typedef to_python_value<T> type;
C++ module definition:
#include <boost/python/module.hpp> #include <boost/python/class.hpp> #include <boost/python/copy_const_reference.hpp> #include <boost/python/return_value_policy.hpp> // classes to wrap struct Bar { int x; } struct Foo { Foo(int x) : { b.x = x; } Bar const& get_bar() const { return b; } private: Bar b; }; // Wrapper code using namespace boost::python; BOOST_PYTHON_MODULE(my_module) { class_<Bar>("Bar"); class_<Foo>("Foo", init<int>()) .def("get_bar", &Foo::get_bar , return_value_policy<copy_const_reference>()) ; }
Python code:
>>> from my_module import * >>> f = Foo(3) # create a Foo object >>> b = f.get_bar() # make a copy of the internal Bar object
copy_non_const_reference
is a model of ResultConverterGenerator
which can be used to wrap C++ functions returning a reference-to-non-const
type such that the referenced value is copied into a new Python object.
namespace boost { namespace python { struct copy_non_const_reference { template <class T> struct apply; }; }}
template <class T> struct apply
T
is U &
for some non-const U
.
typedef to_python_value<T> type
;
C++ module definition:
#include <boost/python/module.hpp> #include <boost/python/class.hpp> #include <boost/python/copy_non_const_reference.hpp> #include <boost/python/return_value_policy.hpp> // classes to wrap struct Bar { int x; } struct Foo { Foo(int x) : { b.x = x; } Bar& get_bar() { return b; } private: Bar b; }; // Wrapper code using namespace boost::python; BOOST_PYTHON_MODULE(my_module) { class_<Bar>("Bar"); class_<Foo>("Foo", init<int>()) .def("get_bar", &Foo::get_bar , return_value_policy<copy_non_const_reference>()) ; }
Python code:
>>> from my_module import * >>> f = Foo(3) # create a Foo object >>> b = f.get_bar() # make a copy of the internal Bar object
manage_new_object
is
a model of ResultConverterGenerator
which can be used to wrap C++ functions which return a pointer to an
object allocated with a new-expression, and expect the caller to take
responsibility for deleting that object.
namespace boost { namespace python { struct manage_new_object { template <class T> struct apply; }; }}
template <class T> struct apply
T
is U*
for some U
.
typedef to_python_indirect<T> type;
In C++:
#include <boost/python/module.hpp> #include <boost/python/class.hpp> #include <boost/python/manage_new_object.hpp> #include <boost/python/return_value_policy.hpp> struct Foo { Foo(int x) : x(x){} int get_x() { return x; } int x; }; Foo* make_foo(int x) { return new Foo(x); } // Wrapper code using namespace boost::python; BOOST_PYTHON_MODULE(my_module) { def("make_foo", make_foo, return_value_policy<manage_new_object>()) class_<Foo>("Foo") .def("get_x", &Foo::get_x) ; }
Python code:
>>> from my_module import * >>> f = make_foo(3) # create a Foo object >>> f.get_x() 3
reference_existing_object
is a model of ResultConverterGenerator
which can be used to wrap C++ functions which return a reference or pointer
to a C++ object. When the wrapped function is called, the value referenced
by its return value is not copied. A new Python object is created which
contains a pointer to the referent, and no attempt is made to ensure
that the lifetime of the referent is at least as long as that of the
corresponding Python object. Thus, it can be highly
dangerous to use reference_existing_object
without additional lifetime management from such models of CallPolicies
as with_custodian_and_ward
. This
class is used in the implementation of return_internal_reference
.
namespace boost { namespace python { struct reference_existing_object { template <class T> struct apply; }; }}
template <class T> struct apply
T
is U&
or U*
for some U
.
typedef to_python_indirect<T, V> type;
, where V is a class whose static
execute function constructs an instance holder containing an unowned
U*
pointing to the referent of the wrapped function's return value.
In C++:
#include <boost/python/module.hpp> #include <boost/python/class.hpp> #include <boost/python/reference_existing_object.hpp> #include <boost/python/return_value_policy.hpp> #include <utility> // classes to wrap struct Singleton { Singleton() : x(0) {} int exchange(int n) // set x and return the old value { std::swap(n, x); return n; } int x; }; Singleton& get_it() { static Singleton just_one; return just_one; } // Wrapper code using namespace boost::python; BOOST_PYTHON_MODULE(singleton) { def("get_it", get_it, return_value_policy<reference_existing_object>()); class_<Singleton>("Singleton") .def("exchange", &Singleton::exchange) ; }
Python code:
>>> import singleton >>> s1 = singleton.get_it() >>> s2 = singleton.get_it() >>> id(s1) == id(s2) # s1 and s2 are not the same object 0 >>> s1.exchange(42) # but they reference the same C++ Singleton 0 >>> s2.exchange(99) 42
return_by_value
is a
model of ResultConverterGenerator
which can be used to wrap C++ functions returning any reference or value
type such that the return value is copied into a new Python object.
namespace boost { namespace python { struct return_by_value { template <class T> struct apply; }; }}
template <class T> struct apply
typedef to_python_value<T> type;
In C++:
#include <boost/python/module.hpp> #include <boost/python/class.hpp> #include <boost/python/return_by_value.hpp> #include <boost/python/return_value_policy.hpp> // classes to wrap struct Bar { }; Bar global_bar; // functions to wrap: Bar b1(); Bar& b2(); Bar const& b3(); // Wrapper code using namespace boost::python; template <class R> void def_void_function(char const* name, R (*f)()) { def(name, f, return_value_policy<return_by_value>()); } BOOST_PYTHON_MODULE(my_module) { class_<Bar>("Bar"); def_void_function("b1", b1); def_void_function("b2", b2); def_void_function("b3", b3); }
Python code:
>>> from my_module import * >>> b = b1() # each of these calls >>> b = b2() # creates a brand >>> b = b3() # new Bar object
return_opaque_pointer is a model of ResultConverterGenerator which can be used to wrap C++ functions returning pointers to undefined types such that the return value is copied into a new Python object.
In addition to specifying the return_opaque_pointer
policy the BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID
macro must be used to define specializations for the type_id
function on the type
pointed to by returned pointer.
namespace boost { namespace python { struct return_opaque_pointer { template <class R> struct apply; }; }}
template <class T> struct apply
detail::opaque_conversion_holder<R>
type;
In C++:
# include <boost/python/return_opaque_pointer.hpp> # include <boost/python/def.hpp> # include <boost/python/module.hpp> # include <boost/python/return_value_policy.hpp> typedef struct opaque_ *opaque; opaque the_op = ((opaque) 0x47110815); opaque get () { return the_op; } void use (opaque op) { if (op != the_op) throw std::runtime_error (std::string ("failed")); } void failuse (opaque op) { if (op == the_op) throw std::runtime_error (std::string ("success")); } BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(opaque_) namespace bpl = boost::python; BOOST_PYTHON_MODULE(opaque_ext) { bpl::def ( "get", &::get, bpl::return_value_policy<bpl::return_opaque_pointer>()); bpl::def ("use", &::use); bpl::def ("failuse", &::failuse); }
Python code:
""" >>> from opaque_ext import * >>> # >>> # Check for correct conversion >>> use(get()) >>> failuse(get()) Traceback (most recent call last): ... RuntimeError: success >>> # >>> # Check that there is no conversion from integers ... >>> use(0) Traceback (most recent call last): ... TypeError: bad argument type for built-in operation >>> # >>> # ... and from strings to opaque objects >>> use("") Traceback (most recent call last): ... TypeError: bad argument type for built-in operation """ def run(args = None): import sys import doctest if args is not None: sys.argv = args return doctest.testmod(sys.modules.get(__name__)) if __name__ == '__main__': print "running..." import sys sys.exit(run()[0])