mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-26 07:02:11 +00:00
Merge pull request #454 from dean0x7d/shared_ptr
Support std::shared_ptr holder type out of the box
This commit is contained in:
commit
77898af0f8
@ -1,7 +1,7 @@
|
||||
Smart pointers
|
||||
##############
|
||||
|
||||
Unique pointers
|
||||
std::unique_ptr
|
||||
===============
|
||||
|
||||
Given a class ``Example`` with Python bindings, it's possible to return
|
||||
@ -28,14 +28,8 @@ The above signature would imply that Python needs to give up ownership of an
|
||||
object that is passed to this function, which is generally not possible (for
|
||||
instance, the object might be referenced elsewhere).
|
||||
|
||||
.. _smart_pointers:
|
||||
|
||||
Reference-counting pointers
|
||||
===========================
|
||||
|
||||
This section explains how to pass values that are wrapped in "smart" pointer
|
||||
types with internal reference counting. For the simpler C++11 unique pointers,
|
||||
refer to the previous section.
|
||||
std::shared_ptr
|
||||
===============
|
||||
|
||||
The binding generator for classes, :class:`class_`, can be passed a template
|
||||
type that denotes a special *holder* type that is used to manage references to
|
||||
@ -53,22 +47,6 @@ following snippet causes ``std::shared_ptr`` to be used instead.
|
||||
|
||||
Note that any particular class can only be associated with a single holder type.
|
||||
|
||||
To enable transparent conversions for functions that take shared pointers as an
|
||||
argument or that return them, a macro invocation similar to the following must
|
||||
be declared at the top level before any binding code:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr<T>);
|
||||
|
||||
.. note::
|
||||
|
||||
The first argument of :func:`PYBIND11_DECLARE_HOLDER_TYPE` should be a
|
||||
placeholder name that is used as a template parameter of the second
|
||||
argument. Thus, feel free to use any identifier, but use it consistently on
|
||||
both sides; also, don't use the name of a type that already exists in your
|
||||
codebase.
|
||||
|
||||
One potential stumbling block when using holder types is that they need to be
|
||||
applied consistently. Can you guess what's broken about the following binding
|
||||
code?
|
||||
@ -139,6 +117,24 @@ There are two ways to resolve this issue:
|
||||
|
||||
class Child : public std::enable_shared_from_this<Child> { };
|
||||
|
||||
.. _smart_pointers:
|
||||
|
||||
Custom smart pointers
|
||||
=====================
|
||||
|
||||
pybind11 supports ``std::unique_ptr`` and ``std::shared_ptr`` right out of the
|
||||
box. For any other custom smart pointer, transparent conversions can be enabled
|
||||
using a macro invocation similar to the following. It must be declared at the
|
||||
level before any binding code:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr<T>);
|
||||
|
||||
The first argument of :func:`PYBIND11_DECLARE_HOLDER_TYPE` should be a
|
||||
placeholder name that is used as a template parameter of the second argument.
|
||||
Thus, feel free to use any identifier, but use it consistently on both sides;
|
||||
also, don't use the name of a type that already exists in your codebase.
|
||||
|
||||
Please take a look at the :ref:`macro_notes` before using this feature.
|
||||
|
||||
|
@ -55,6 +55,8 @@ Breaking changes queued for v2.0.0 (Not yet released)
|
||||
``py::str s = "1 + 2 = {}"_s.format(3);``
|
||||
* Attribute and item accessors now have a more complete interface which makes it possible
|
||||
to chain attributes ``obj.attr("a")[key].attr("b").attr("method")(1, 2, 3)```.
|
||||
* Added built-in support for ``std::shared_ptr`` holder type. There is no more need
|
||||
to do it manually via ``PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr<T>)``.
|
||||
* Various minor improvements of library internals (no user-visible changes)
|
||||
|
||||
1.8.1 (July 12, 2016)
|
||||
|
@ -383,12 +383,6 @@ public:
|
||||
operator type&() { return value; } \
|
||||
template <typename _T> using cast_op_type = pybind11::detail::cast_op_type<_T>
|
||||
|
||||
#define PYBIND11_DECLARE_HOLDER_TYPE(type, holder_type) \
|
||||
namespace pybind11 { namespace detail { \
|
||||
template <typename type> class type_caster<holder_type> \
|
||||
: public type_caster_holder<type, holder_type> { }; \
|
||||
}}
|
||||
|
||||
|
||||
template <typename T>
|
||||
struct type_caster<T, enable_if_t<std::is_arithmetic<T>::value>> {
|
||||
@ -898,6 +892,18 @@ protected:
|
||||
holder_type holder;
|
||||
};
|
||||
|
||||
/// Specialize for the common std::shared_ptr, so users don't need to
|
||||
template <typename T>
|
||||
class type_caster<std::shared_ptr<T>> : public type_caster_holder<T, std::shared_ptr<T>> { };
|
||||
|
||||
/// Create a specialization for custom holder types (silently ignores std::shared_ptr)
|
||||
#define PYBIND11_DECLARE_HOLDER_TYPE(type, holder_type) \
|
||||
namespace pybind11 { namespace detail { \
|
||||
template <typename type> \
|
||||
class type_caster<holder_type, enable_if_t<!is_shared_ptr<holder_type>::value>> \
|
||||
: public type_caster_holder<type, holder_type> { }; \
|
||||
}}
|
||||
|
||||
// PYBIND11_DECLARE_HOLDER_TYPE holder types:
|
||||
template <typename base, typename holder> struct is_holder_type :
|
||||
std::is_base_of<detail::type_caster_holder<base, holder>, detail::type_caster<holder>> {};
|
||||
|
@ -417,6 +417,10 @@ using is_template_base_of = decltype(is_template_base_of_impl<Base>::check((T*)n
|
||||
struct is_template_base_of : decltype(is_template_base_of_impl<Base>::check((T*)nullptr)) { };
|
||||
#endif
|
||||
|
||||
/// Check if T is std::shared_ptr<U> where U can be anything
|
||||
template <typename T> struct is_shared_ptr : std::false_type { };
|
||||
template <typename U> struct is_shared_ptr<std::shared_ptr<U>> : std::true_type { };
|
||||
|
||||
/// Ignore that a variable is unused in compiler warnings
|
||||
inline void ignore_unused(const int *) { }
|
||||
|
||||
|
@ -9,7 +9,6 @@
|
||||
|
||||
#include "pybind11_tests.h"
|
||||
|
||||
PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr<T>);
|
||||
|
||||
template <int N> class BreaksBase {};
|
||||
template <int N> class BreaksTramp : public BreaksBase<N> {};
|
||||
|
@ -12,7 +12,6 @@
|
||||
#include <pybind11/stl.h>
|
||||
#include <pybind11/operators.h>
|
||||
|
||||
PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr<T>);
|
||||
|
||||
#define TRACKERS(CLASS) CLASS() { print_default_created(this); } ~CLASS() { print_destroyed(this); }
|
||||
struct NestABase { int value = -2; TRACKERS(NestABase) };
|
||||
|
@ -10,7 +10,6 @@
|
||||
|
||||
#include "pybind11_tests.h"
|
||||
|
||||
PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr<T>);
|
||||
|
||||
struct Base1 {
|
||||
Base1(int i) : i(i) { }
|
||||
|
@ -82,8 +82,9 @@ private:
|
||||
};
|
||||
|
||||
/// Make pybind aware of the ref-counted wrapper type (s)
|
||||
PYBIND11_DECLARE_HOLDER_TYPE(T, ref<T>);
|
||||
PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr<T>);
|
||||
PYBIND11_DECLARE_HOLDER_TYPE(T, ref<T>); // Required for custom holder type
|
||||
PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr<T>); // Not required any more for std::shared_ptr,
|
||||
// but it should compile without error
|
||||
|
||||
Object *make_object_1() { return new MyObject1(1); }
|
||||
ref<Object> make_object_2() { return new MyObject1(2); }
|
||||
|
Loading…
Reference in New Issue
Block a user