@@ -190,6 +190,23 @@ class object_api : public pyobject_tag {
190
190
bool rich_compare (object_api const &other, int value) const ;
191
191
};
192
192
193
+ template <typename T, typename SFINAE = void >
194
+ struct has_member_ob_refcnt : std::false_type {};
195
+
196
+ template <typename T>
197
+ struct has_member_ob_refcnt <T, decltype ((void ) T::ob_refcnt, void ())> : std::true_type {};
198
+
199
+ template <typename T, typename SFINAE = void >
200
+ struct is_c_api_py_object_pointer : std::false_type {};
201
+
202
+ template <typename T>
203
+ struct is_c_api_py_object_pointer <
204
+ T,
205
+ detail::enable_if_t <
206
+ std::is_pointer<T>::value
207
+ && detail::has_member_ob_refcnt<typename std::remove_pointer<T>::type>::value>>
208
+ : std::true_type {};
209
+
193
210
PYBIND11_NAMESPACE_END (detail)
194
211
195
212
#if !defined(PYBIND11_HANDLE_REF_DEBUG) && !defined(NDEBUG)
@@ -212,8 +229,18 @@ class handle : public detail::object_api<handle> {
212
229
// / The default constructor creates a handle with a ``nullptr``-valued pointer
213
230
handle () = default ;
214
231
// / Creates a ``handle`` from the given raw Python object pointer
232
+ // / Not using ``handle(PyObject *ptr)`` to avoid implicit conversion from ``0``.
233
+ template <typename T,
234
+ detail::enable_if_t <detail::is_c_api_py_object_pointer<T>::value
235
+ || std::is_same<T, std::nullptr_t >::value,
236
+ int > = 0 >
215
237
// NOLINTNEXTLINE(google-explicit-constructor)
216
- handle (PyObject *ptr) : m_ptr(ptr) {} // Allow implicit conversion from PyObject*
238
+ handle (/* PyObject* */ T ptr) : m_ptr(ptr) {} // Allow implicit conversion from PyObject*
239
+
240
+ handle (const handle &) = default ;
241
+ handle (handle &&) = default ;
242
+ handle &operator =(const handle &) = default ;
243
+ handle &operator =(handle &&) = default ;
217
244
218
245
// / Return the underlying ``PyObject *`` pointer
219
246
PyObject *ptr () const { return m_ptr; }
0 commit comments