@@ -43,7 +43,7 @@ using tuple_accessor = accessor<accessor_policies::tuple_item>;
4343
4444// / Tag and check to identify a class which implements the Python object API
4545class pyobject_tag { };
46- template <typename T> using is_pyobject = std::is_base_of<pyobject_tag, T >;
46+ template <typename T> using is_pyobject = std::is_base_of<pyobject_tag, typename std::remove_reference<T>::type >;
4747
4848// / Mixin which adds common functions to handle, object and various accessors.
4949// / The only requirement for `Derived` is to implement `PyObject *Derived::ptr() const`.
@@ -81,7 +81,7 @@ NAMESPACE_END(detail)
8181class handle : public detail::object_api<handle> {
8282public:
8383 handle () = default ;
84- handle (PyObject *ptr) : m_ptr (ptr) { }
84+ handle (PyObject *ptr) : m_ptr (ptr) { } // Allow implicit conversion from PyObject*
8585
8686 PyObject *ptr () const { return m_ptr; }
8787 PyObject *&ptr () { return m_ptr; }
@@ -224,19 +224,36 @@ inline handle get_function(handle value) {
224224 return value;
225225}
226226
227+ // Helper aliases/functions to support implicit casting of values given to python accessors/methods.
228+ // When given a pyobject, this simply returns the pyobject as-is; for other C++ type, the value goes
229+ // through pybind11::cast(obj) to convert it to an `object`.
230+ template <typename T, enable_if_t <is_pyobject<T>::value, int > = 0 >
231+ auto object_or_cast (T &&o) -> decltype(std::forward<T>(o)) { return std::forward<T>(o); }
232+ // The following casting version is implemented in cast.h:
233+ template <typename T, enable_if_t <!is_pyobject<T>::value, int > = 0 >
234+ object object_or_cast (T &&o);
235+ // Match a PyObject*, which we want to convert directly to handle via its converting constructor
236+ inline handle object_or_cast (PyObject *ptr) { return ptr; }
237+
238+
227239template <typename Policy>
228240class accessor : public object_api <accessor<Policy>> {
229241 using key_type = typename Policy::key_type;
230242
231243public:
232244 accessor (handle obj, key_type key) : obj(obj), key(std::move(key)) { }
233245
246+ // accessor overload required to override default assignment operator (templates are not allowed
247+ // to replace default compiler-generated assignments).
234248 void operator =(const accessor &a) && { std::move (*this ).operator =(handle (a)); }
235249 void operator =(const accessor &a) & { operator =(handle (a)); }
236- void operator =(const object &o) && { std::move (*this ).operator =(handle (o)); }
237- void operator =(const object &o) & { operator =(handle (o)); }
238- void operator =(handle value) && { Policy::set (obj, key, value); }
239- void operator =(handle value) & { get_cache () = reinterpret_borrow<object>(value); }
250+
251+ template <typename T> void operator =(T &&value) && {
252+ Policy::set (obj, key, object_or_cast (std::forward<T>(value)));
253+ }
254+ template <typename T> void operator =(T &&value) & {
255+ get_cache () = reinterpret_borrow<object>(object_or_cast (std::forward<T>(value)));
256+ }
240257
241258 template <typename T = Policy>
242259 PYBIND11_DEPRECATED (" Use of obj.attr(...) as bool is deprecated in favor of pybind11::hasattr(obj, ...)" )
@@ -773,7 +790,9 @@ class list : public object {
773790 }
774791 size_t size () const { return (size_t ) PyList_Size (m_ptr); }
775792 detail::list_accessor operator [](size_t index) const { return {*this , index}; }
776- void append (handle h) const { PyList_Append (m_ptr, h.ptr ()); }
793+ template <typename T> void append (T &&val) const {
794+ PyList_Append (m_ptr, detail::object_or_cast (std::forward<T>(val)).ptr ());
795+ }
777796};
778797
779798class args : public tuple { PYBIND11_OBJECT_DEFAULT(args, tuple, PyTuple_Check) };
@@ -786,7 +805,9 @@ class set : public object {
786805 if (!m_ptr) pybind11_fail (" Could not allocate set object!" );
787806 }
788807 size_t size () const { return (size_t ) PySet_Size (m_ptr); }
789- bool add (const object &object) const { return PySet_Add (m_ptr, object.ptr ()) == 0 ; }
808+ template <typename T> bool add (T &&val) const {
809+ return PySet_Add (m_ptr, detail::object_or_cast (std::forward<T>(val)).ptr ()) == 0 ;
810+ }
790811 void clear () const { PySet_Clear (m_ptr); }
791812};
792813
0 commit comments