From 5d28dd1194aaf22002c4872ae8e91b7d5a993f4c Mon Sep 17 00:00:00 2001 From: Dean Moldovan Date: Tue, 18 Oct 2016 13:56:33 +0200 Subject: [PATCH] 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)`. Existing ones will still compile without error -- they will just be ignored silently. Resolves #446. --- docs/advanced/smart_ptrs.rst | 46 +++++++++++++---------------- docs/changelog.rst | 2 ++ include/pybind11/cast.h | 18 +++++++---- include/pybind11/common.h | 4 +++ tests/test_class_args.cpp | 1 - tests/test_issues.cpp | 1 - tests/test_multiple_inheritance.cpp | 1 - tests/test_smart_ptr.cpp | 5 ++-- 8 files changed, 42 insertions(+), 36 deletions(-) diff --git a/docs/advanced/smart_ptrs.rst b/docs/advanced/smart_ptrs.rst index 97dc7ab70..6e8c9de36 100644 --- a/docs/advanced/smart_ptrs.rst +++ b/docs/advanced/smart_ptrs.rst @@ -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); - -.. 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 { }; +.. _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); + +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. diff --git a/docs/changelog.rst b/docs/changelog.rst index 647622448..0c3ec1bcb 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -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)``. * Various minor improvements of library internals (no user-visible changes) 1.8.1 (July 12, 2016) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 91912de75..f3690262e 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -383,12 +383,6 @@ public: operator type&() { return value; } \ template using cast_op_type = pybind11::detail::cast_op_type<_T> -#define PYBIND11_DECLARE_HOLDER_TYPE(type, holder_type) \ - namespace pybind11 { namespace detail { \ - template class type_caster \ - : public type_caster_holder { }; \ - }} - template struct type_caster::value>> { @@ -898,6 +892,18 @@ protected: holder_type holder; }; +/// Specialize for the common std::shared_ptr, so users don't need to +template +class type_caster> : public type_caster_holder> { }; + +/// 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 \ + class type_caster::value>> \ + : public type_caster_holder { }; \ + }} + // PYBIND11_DECLARE_HOLDER_TYPE holder types: template struct is_holder_type : std::is_base_of, detail::type_caster> {}; diff --git a/include/pybind11/common.h b/include/pybind11/common.h index 40cee8703..6f79f91ba 100644 --- a/include/pybind11/common.h +++ b/include/pybind11/common.h @@ -417,6 +417,10 @@ using is_template_base_of = decltype(is_template_base_of_impl::check((T*)n struct is_template_base_of : decltype(is_template_base_of_impl::check((T*)nullptr)) { }; #endif +/// Check if T is std::shared_ptr where U can be anything +template struct is_shared_ptr : std::false_type { }; +template struct is_shared_ptr> : std::true_type { }; + /// Ignore that a variable is unused in compiler warnings inline void ignore_unused(const int *) { } diff --git a/tests/test_class_args.cpp b/tests/test_class_args.cpp index c1207016c..e18b39db2 100644 --- a/tests/test_class_args.cpp +++ b/tests/test_class_args.cpp @@ -9,7 +9,6 @@ #include "pybind11_tests.h" -PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr); template class BreaksBase {}; template class BreaksTramp : public BreaksBase {}; diff --git a/tests/test_issues.cpp b/tests/test_issues.cpp index f2d9a51a1..29c4057f1 100644 --- a/tests/test_issues.cpp +++ b/tests/test_issues.cpp @@ -12,7 +12,6 @@ #include #include -PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr); #define TRACKERS(CLASS) CLASS() { print_default_created(this); } ~CLASS() { print_destroyed(this); } struct NestABase { int value = -2; TRACKERS(NestABase) }; diff --git a/tests/test_multiple_inheritance.cpp b/tests/test_multiple_inheritance.cpp index 7a11d44d1..3cb12b68d 100644 --- a/tests/test_multiple_inheritance.cpp +++ b/tests/test_multiple_inheritance.cpp @@ -10,7 +10,6 @@ #include "pybind11_tests.h" -PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr); struct Base1 { Base1(int i) : i(i) { } diff --git a/tests/test_smart_ptr.cpp b/tests/test_smart_ptr.cpp index 3d3d0ff36..7d50f0dd7 100644 --- a/tests/test_smart_ptr.cpp +++ b/tests/test_smart_ptr.cpp @@ -82,8 +82,9 @@ private: }; /// Make pybind aware of the ref-counted wrapper type (s) -PYBIND11_DECLARE_HOLDER_TYPE(T, ref); -PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr); +PYBIND11_DECLARE_HOLDER_TYPE(T, ref); // Required for custom holder type +PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr); // Not required any more for std::shared_ptr, + // but it should compile without error Object *make_object_1() { return new MyObject1(1); } ref make_object_2() { return new MyObject1(2); }