Skip to content

cast: Add is_generic_type<T> #3857

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions include/pybind11/cast.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,15 @@ class type_caster : public type_caster_base<type> {};
template <typename type>
using make_caster = type_caster<intrinsic_t<type>>;

template <typename T>
struct is_generic_type<T, enable_if_t<std::is_base_of<type_caster_generic, make_caster<T>>::value>>
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From @rwgk in #2950

Two questions:

  1. Will this work if I add another specialization pair for is_base_of<smart_holder_type_caster_base_tag, ...>?

  2. What do you think about choosing a different name, to connect to the intended purpose instead of pegging the name on type_caster_generic, e.g. is_iterable_t_compatible? (Otherwise it will get really confusing that generic is connected to smart_holder_type_caster.)

(1) Yup! Can simply add the specialization and it should work out of the box.
(2) I know that was for prior PR; I believe this trait is more agnostic. See PR overview for rationale.

: public std::true_type {};

template <typename T>
struct is_generic_type<T,
enable_if_t<!std::is_base_of<type_caster_generic, make_caster<T>>::value>>
: public std::false_type {};

// Shortcut for calling a caster's `cast_op_type` cast operator for casting a type_caster to a T
template <typename T>
typename make_caster<T>::template cast_op_type<T> cast_op(make_caster<T> &caster) {
Expand Down
9 changes: 8 additions & 1 deletion include/pybind11/pytypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ PYBIND11_NAMESPACE_BEGIN(detail)
class args_proxy;
bool isinstance_generic(handle obj, const std::type_info &tp);

// Indicates that type is generic and and does not have a specialized
// `type_caster<>` specialization. Defined in `cast.h`.
template <typename T, typename SFINAE = void>
struct is_generic_type;

// Accessor forward declarations
template <typename Policy>
class accessor;
Expand Down Expand Up @@ -476,7 +481,7 @@ inline void raise_from(error_already_set &err, PyObject *type, const char *messa
/** \ingroup python_builtins
\rst
Return true if ``obj`` is an instance of ``T``. Type ``T`` must be a subclass of
`object` or a class which was exposed to Python as ``py::class_<T>``.
`object` or a class which was exposed to Python as ``py::class_<T>`` (generic).
\endrst */
template <typename T, detail::enable_if_t<std::is_base_of<object, T>::value, int> = 0>
bool isinstance(handle obj) {
Expand All @@ -485,6 +490,8 @@ bool isinstance(handle obj) {

template <typename T, detail::enable_if_t<!std::is_base_of<object, T>::value, int> = 0>
bool isinstance(handle obj) {
static_assert(detail::is_generic_type<T>::value,
"isinstance<T>() requires specialization for this type");
return detail::isinstance_generic(obj, typeid(T));
}

Expand Down