diff --git a/doc/v2/reference.html b/doc/v2/reference.html index 18eace54..50dfd1e8 100644 --- a/doc/v2/reference.html +++ b/doc/v2/reference.html @@ -973,6 +973,22 @@ + +
register_ptr_to_python.hpp
+ +
+
+
Functions
+ +
+
+
register_ptr_to_python
+
+
+
+
+

Utility and Infrastructure

diff --git a/doc/v2/register_ptr_to_python.html b/doc/v2/register_ptr_to_python.html new file mode 100644 index 00000000..67e765ad --- /dev/null +++ b/doc/v2/register_ptr_to_python.html @@ -0,0 +1,160 @@ + + + + +Boost.Python - <register_ptr_to_python.hpp> + + + + + + + +
+

+

+
+

Boost.Python

+

Header <register_ptr_to_python.hpp>

+
+
+

Contents

+
+
Introduction
+
Functions
+
+
register_ptr_to_python
+
+ +
Example(s)
+ +
+
+

Introduction

+

+ <boost/python/converter/register_ptr_to_python.hpp> + supplies register_ptr_to_python, a function template + which registers a conversion for smart pointers to Python. The + resulting Python object holds a copy of the converted smart pointer, + but behaves as though it were a wrapped copy of the pointee. If + the pointee type has virtual functions and the class representing + its dynamic (most-derived) type has been wrapped, the Python object + will be an instance of the wrapper for the most-derived type. More than + one smart pointer type for a pointee's class can be registered. +

+

+ Note that in order to convert a Python X object to a + smart_ptr<X>& (non-const reference), the embedded C++ + object must be held by smart_ptr<X>, and that when wrapped + objects are created by calling the constructor from Python, how they are held + is determined by the HeldType parameter to class_<...> + instances. +

+ +

Functions

+
+template <class P>
+void register_ptr_to_python() 
+
+
+
Requires: P is the type of the smart pointer, + for example smart_ptr<X>. +
+
Effects: Allows conversions to-python of smart_ptr<X> + instances. +
+
+ +

Example(s)

+ +

C++ Wrapper Code

+ +Here is an example of a module that contains a class A with +virtual functions and some functions that work with +boost::shared_ptr<A>. + +
+struct A
+{
+    virtual int f() { return 0; }
+};
+
+shared_ptr<A> New() { return shared_ptr<A>( new A() ); }
+
+int Ok( const shared_ptr<A>& a ) { return a->f(); }
+
+int Fail( shared_ptr<A>& a ) { return a->f(); }
+
+struct A_Wrapper: A
+{
+    A_Wrapper(PyObject* self_): self(self_) {}
+    int f() { return call_method<int>(self, "f"); }    
+    int default_f() { return A::f(); }    
+    PyObject* self;
+};
+
+BOOST_PYTHON_MODULE(register_ptr)
+{
+    class_<A, A_Wrapper>("A")
+        .def("f", &A::f, &A_Wrapper::default_f)
+    ;
+    
+    def("New", &New);
+    def("Ok", &Call);
+    def("Fail", &Fail);
+    
+    register_ptr_to_python< shared_ptr<A> >();
+} 
+
+ +

Python Code

+ +
+>>> from register_ptr import *
+>>> a = A()
+>>> Ok(a)     # ok, passed as shared_ptr<A>
+0
+>>> Fail(a)   # passed as shared_ptr<A>&, and was created in Python!
+Traceback (most recent call last):
+  File "<stdin>", line 1, in ?
+TypeError: bad argument type for built-in operation
+>>>
+>>> na = New()   # now "na" is actually a shared_ptr<A> 
+>>> Ok(a)
+0
+>>> Fail(a)
+0
+>>>
+
+ +If shared_ptr<A> is registered as follows: + +
+    class_<A, A_Wrapper, shared_ptr<A> >("A")
+        .def("f", &A::f, &A_Wrapper::default_f)
+    ;            
+
+ +There will be an error when trying to convert shared_ptr<A> to +shared_ptr<A_Wrapper>: + +
+>>> a = New()
+Traceback (most recent call last):
+File "<stdin>", line 1, in ?
+TypeError: No to_python (by-value) converter found for C++ type: class boost::shared_ptr<struct A>
+>>>    
+
+ +

Revised + + 24 Jun, 2003 + +

+

© Copyright Dave Abrahams + 2002. All Rights Reserved.

+ + + + diff --git a/include/boost/python.hpp b/include/boost/python.hpp index bdca0b2f..5df41117 100644 --- a/include/boost/python.hpp +++ b/include/boost/python.hpp @@ -63,5 +63,6 @@ # include # include # include +# include #endif // PYTHON_DWA2002810_HPP diff --git a/include/boost/python/converter/register_ptr_to_python.hpp b/include/boost/python/converter/register_ptr_to_python.hpp new file mode 100644 index 00000000..0842e1c1 --- /dev/null +++ b/include/boost/python/converter/register_ptr_to_python.hpp @@ -0,0 +1,31 @@ +// Copyright David Abrahams 2002. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef REGISTER_PTR_TO_PYTHON_HPP +#define REGISTER_PTR_TO_PYTHON_HPP + +#include +#include + +namespace boost { namespace python { + +template +void register_ptr_to_python(P* = 0) +{ + typedef typename boost::python::pointee

::type X; + objects::class_value_wrapper< + P + , objects::make_ptr_instance< + X + , objects::pointer_holder + > + >(); +} + +}} // namespace boost::python + +#endif // REGISTER_PTR_TO_PYTHON_HPP + + diff --git a/test/register_ptr.cpp b/test/register_ptr.cpp new file mode 100644 index 00000000..f65599d9 --- /dev/null +++ b/test/register_ptr.cpp @@ -0,0 +1,52 @@ + +#include +#include + +using namespace boost; +using namespace python; + +struct A +{ + virtual int f() { return 0; } +}; + +shared_ptr New() { return shared_ptr( new A() ); } + +int Call( const shared_ptr & a ) +{ + return a->f(); +} + +int Fail( shared_ptr & a ) +{ + return a->f(); +} + +struct A_Wrapper: A +{ + A_Wrapper(PyObject* self_): self(self_) {} + A_Wrapper(PyObject* self_, const A& a): self(self_), A(a) {} + + int f() + { + return call_method(self, "f"); + } + + int default_f() + { + return A::f(); + } + + PyObject* self; +}; + +BOOST_PYTHON_MODULE(register_ptr) +{ + class_("A") + .def("f", &A::f, &A_Wrapper::default_f) + ; + register_ptr_to_python< shared_ptr >(); + def("New", &New); + def("Call", &Call); + def("Fail", &Fail); +} diff --git a/test/register_ptr_test.py b/test/register_ptr_test.py new file mode 100644 index 00000000..f0472993 --- /dev/null +++ b/test/register_ptr_test.py @@ -0,0 +1,22 @@ +import unittest +from register_ptr import * + +class RegisterPtrTest(unittest.TestCase): + + def testIt(self): + + class B(A): + def f(self): + return 10 + + a = New() # this must work + b = B() + self.assertEqual(Call(a), 0) + self.assertEqual(Call(b), 10) + def fails(): + Fail(A()) + self.assertRaises(TypeError, fails) + self.assertEqual(Fail(a), 0) # ok, since a is held by shared_ptr + +if __name__ == '__main__': + unittest.main()