mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-25 06:35:12 +00:00
Support std::shared_ptr holder type out of the box
With this there is no more need for manual user declarations like `PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr<T>)`. Existing ones will still compile without error -- they will just be ignored silently. Resolves #446.
This commit is contained in:
parent
f0b0df58a9
commit
5d28dd1194
@ -1,7 +1,7 @@
|
|||||||
Smart pointers
|
Smart pointers
|
||||||
##############
|
##############
|
||||||
|
|
||||||
Unique pointers
|
std::unique_ptr
|
||||||
===============
|
===============
|
||||||
|
|
||||||
Given a class ``Example`` with Python bindings, it's possible to return
|
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
|
object that is passed to this function, which is generally not possible (for
|
||||||
instance, the object might be referenced elsewhere).
|
instance, the object might be referenced elsewhere).
|
||||||
|
|
||||||
.. _smart_pointers:
|
std::shared_ptr
|
||||||
|
===============
|
||||||
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.
|
|
||||||
|
|
||||||
The binding generator for classes, :class:`class_`, can be passed a template
|
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
|
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.
|
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
|
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
|
applied consistently. Can you guess what's broken about the following binding
|
||||||
code?
|
code?
|
||||||
@ -139,6 +117,24 @@ There are two ways to resolve this issue:
|
|||||||
|
|
||||||
class Child : public std::enable_shared_from_this<Child> { };
|
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.
|
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);``
|
``py::str s = "1 + 2 = {}"_s.format(3);``
|
||||||
* Attribute and item accessors now have a more complete interface which makes it possible
|
* 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)```.
|
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)
|
* Various minor improvements of library internals (no user-visible changes)
|
||||||
|
|
||||||
1.8.1 (July 12, 2016)
|
1.8.1 (July 12, 2016)
|
||||||
|
@ -383,12 +383,6 @@ public:
|
|||||||
operator type&() { return value; } \
|
operator type&() { return value; } \
|
||||||
template <typename _T> using cast_op_type = pybind11::detail::cast_op_type<_T>
|
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>
|
template <typename T>
|
||||||
struct type_caster<T, enable_if_t<std::is_arithmetic<T>::value>> {
|
struct type_caster<T, enable_if_t<std::is_arithmetic<T>::value>> {
|
||||||
@ -898,6 +892,18 @@ protected:
|
|||||||
holder_type holder;
|
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:
|
// PYBIND11_DECLARE_HOLDER_TYPE holder types:
|
||||||
template <typename base, typename holder> struct is_holder_type :
|
template <typename base, typename holder> struct is_holder_type :
|
||||||
std::is_base_of<detail::type_caster_holder<base, holder>, detail::type_caster<holder>> {};
|
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)) { };
|
struct is_template_base_of : decltype(is_template_base_of_impl<Base>::check((T*)nullptr)) { };
|
||||||
#endif
|
#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
|
/// Ignore that a variable is unused in compiler warnings
|
||||||
inline void ignore_unused(const int *) { }
|
inline void ignore_unused(const int *) { }
|
||||||
|
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
|
|
||||||
#include "pybind11_tests.h"
|
#include "pybind11_tests.h"
|
||||||
|
|
||||||
PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr<T>);
|
|
||||||
|
|
||||||
template <int N> class BreaksBase {};
|
template <int N> class BreaksBase {};
|
||||||
template <int N> class BreaksTramp : public BreaksBase<N> {};
|
template <int N> class BreaksTramp : public BreaksBase<N> {};
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
#include <pybind11/stl.h>
|
#include <pybind11/stl.h>
|
||||||
#include <pybind11/operators.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); }
|
#define TRACKERS(CLASS) CLASS() { print_default_created(this); } ~CLASS() { print_destroyed(this); }
|
||||||
struct NestABase { int value = -2; TRACKERS(NestABase) };
|
struct NestABase { int value = -2; TRACKERS(NestABase) };
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
|
|
||||||
#include "pybind11_tests.h"
|
#include "pybind11_tests.h"
|
||||||
|
|
||||||
PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr<T>);
|
|
||||||
|
|
||||||
struct Base1 {
|
struct Base1 {
|
||||||
Base1(int i) : i(i) { }
|
Base1(int i) : i(i) { }
|
||||||
|
@ -82,8 +82,9 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Make pybind aware of the ref-counted wrapper type (s)
|
/// Make pybind aware of the ref-counted wrapper type (s)
|
||||||
PYBIND11_DECLARE_HOLDER_TYPE(T, ref<T>);
|
PYBIND11_DECLARE_HOLDER_TYPE(T, ref<T>); // Required for custom holder type
|
||||||
PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr<T>);
|
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); }
|
Object *make_object_1() { return new MyObject1(1); }
|
||||||
ref<Object> make_object_2() { return new MyObject1(2); }
|
ref<Object> make_object_2() { return new MyObject1(2); }
|
||||||
|
Loading…
Reference in New Issue
Block a user