@@ -26,6 +26,11 @@ PYBIND11_NAMESPACE_BEGIN(detail)
26
26
class args_proxy;
27
27
inline bool isinstance_generic (handle obj, const std::type_info &tp);
28
28
29
+ // Indicates that type is generic and and does not have a specialized
30
+ // `type_caster<>` specialization. Defined in `cast.h`.
31
+ template <typename T, typename SFINAE = void >
32
+ struct is_generic_type ;
33
+
29
34
// Accessor forward declarations
30
35
template <typename Policy> class accessor ;
31
36
namespace accessor_policies {
@@ -380,13 +385,18 @@ class error_already_set : public std::runtime_error {
380
385
/* * \ingroup python_builtins
381
386
\rst
382
387
Return true if ``obj`` is an instance of ``T``. Type ``T`` must be a subclass of
383
- `object` or a class which was exposed to Python as ``py::class_<T>``.
388
+ `object` or a class which was exposed to Python as ``py::class_<T>`` (generic) .
384
389
\endrst */
385
390
template <typename T, detail::enable_if_t <std::is_base_of<object, T>::value, int > = 0 >
386
391
bool isinstance (handle obj) { return T::check_ (obj); }
387
392
388
393
template <typename T, detail::enable_if_t <!std::is_base_of<object, T>::value, int > = 0 >
389
- bool isinstance (handle obj) { return detail::isinstance_generic (obj, typeid (T)); }
394
+ bool isinstance (handle obj) {
395
+ static_assert (
396
+ detail::is_generic_type<T>::value,
397
+ " isisntance<T>() requires specialization for this type" );
398
+ return detail::isinstance_generic (obj, typeid (T));
399
+ }
390
400
391
401
template <> inline bool isinstance<handle>(handle) = delete ;
392
402
template <> inline bool isinstance<object>(handle obj) { return obj.ptr () != nullptr ; }
@@ -753,6 +763,39 @@ inline bool PyIterable_Check(PyObject *obj) {
753
763
}
754
764
}
755
765
766
+ template <typename T>
767
+ bool PyIterableT_Check (PyObject *obj) {
768
+ static_assert (
769
+ is_generic_type<T>::value || is_pyobject<T>::value,
770
+ " iterable_t can only be used with pyobjects and generic types "
771
+ " (py::class_<T>)" );
772
+ PyObject *iter = PyObject_GetIter (obj);
773
+ if (iter) {
774
+ if (iter == obj) {
775
+ // If they are the same, then that's bad! For now, just throw a
776
+ // cast error.
777
+ Py_DECREF (iter);
778
+ throw cast_error (
779
+ " iterable_t<T> cannot be used with exhausitble iterables "
780
+ " (e.g., iterators, generators)." );
781
+ }
782
+ bool good = true ;
783
+ // Now that we know that the iterable `obj` will not be exhausted,
784
+ // let's check the contained types.
785
+ for (handle h : handle (iter)) {
786
+ if (!isinstance<T>(h)) {
787
+ good = false ;
788
+ break ;
789
+ }
790
+ }
791
+ Py_DECREF (iter);
792
+ return good;
793
+ } else {
794
+ PyErr_Clear ();
795
+ return false ;
796
+ }
797
+ }
798
+
756
799
inline bool PyNone_Check (PyObject *o) { return o == Py_None; }
757
800
inline bool PyEllipsis_Check (PyObject *o) { return o == Py_Ellipsis; }
758
801
@@ -941,6 +984,20 @@ class iterable : public object {
941
984
PYBIND11_OBJECT_DEFAULT (iterable, object, detail::PyIterable_Check)
942
985
};
943
986
987
+ // / Provides similar interface to `iterable`, but constraining the intended
988
+ // / type.
989
+ // / @warning Due to technical reasons, this is constrained in two ways:
990
+ // / - Due to how `isinstance<T>()` works, this does *not* work for iterables of
991
+ // / type-converted values (e.g. `int`).
992
+ // / - Because we must check the contained types within the iterable (for
993
+ // / overloads), we must iterate through the iterable. For this reason, the
994
+ // / iterable should *not* be exhaustible (e.g., iterator, generator).
995
+ template <typename T>
996
+ class iterable_t : public iterable {
997
+ public:
998
+ PYBIND11_OBJECT_DEFAULT (iterable_t , iterable, detail::PyIterableT_Check<T>)
999
+ };
1000
+
944
1001
class bytes ;
945
1002
946
1003
class str : public object {
0 commit comments