mirror of
https://github.com/pybind/pybind11.git
synced 2026-05-14 02:03:34 +00:00
Allow passing base types as a template parameter
This allows a slightly cleaner base type specification of:
py::class_<Type, Base>("Type")
as an alternative to
py::class_<Type>("Type", py::base<Base>())
As with the other template parameters, the order relative to the holder
or trampoline types doesn't matter.
This also includes a compile-time assertion failure if attempting to
specify more than one base class (but is easily extendible to support
multiple inheritance, someday, by updating the class_selector::set_bases
function to set multiple bases).
This commit is contained in:
@@ -798,12 +798,12 @@ protected:
|
||||
holder_type holder;
|
||||
};
|
||||
|
||||
// PYBIND11_DECLARE_HOLDER_TYPE holder types:
|
||||
template <typename base, typename holder> struct is_holder_type :
|
||||
// PYBIND11_DECLARE_HOLDER_TYPE holder types:
|
||||
std::conditional<std::is_base_of<detail::type_caster_holder<base, holder>, detail::type_caster<holder>>::value,
|
||||
std::true_type,
|
||||
std::false_type>::type {};
|
||||
template <typename base, typename deleter> struct is_holder_type<base, std::unique_ptr<base, deleter>> : std::true_type {};
|
||||
std::is_base_of<detail::type_caster_holder<base, holder>, detail::type_caster<holder>> {};
|
||||
// Specialization for always-supported unique_ptr holders:
|
||||
template <typename base, typename deleter> struct is_holder_type<base, std::unique_ptr<base, deleter>> :
|
||||
std::true_type {};
|
||||
|
||||
template <typename T> struct handle_type_name { static PYBIND11_DESCR name() { return _<T>(); } };
|
||||
template <> struct handle_type_name<bytes> { static PYBIND11_DESCR name() { return _(PYBIND11_BYTES_NAME); } };
|
||||
|
||||
@@ -358,20 +358,20 @@ template <template<typename> class P, typename T, typename... Ts>
|
||||
struct any_of_t<P, T, Ts...> : conditional_t<P<T>::value, std::true_type, any_of_t<P, Ts...>> { };
|
||||
#endif
|
||||
|
||||
// Extracts the first type from the template parameter pack matching the predicate, or void if none match.
|
||||
template <template<class> class Predicate, class... Ts> struct first_of;
|
||||
template <template<class> class Predicate> struct first_of<Predicate> {
|
||||
using type = void;
|
||||
// Extracts the first type from the template parameter pack matching the predicate, or Default if none match.
|
||||
template <template<class> class Predicate, class Default, class... Ts> struct first_of;
|
||||
template <template<class> class Predicate, class Default> struct first_of<Predicate, Default> {
|
||||
using type = Default;
|
||||
};
|
||||
template <template<class> class Predicate, class T, class... Ts>
|
||||
struct first_of<Predicate, T, Ts...> {
|
||||
template <template<class> class Predicate, class Default, class T, class... Ts>
|
||||
struct first_of<Predicate, Default, T, Ts...> {
|
||||
using type = typename std::conditional<
|
||||
Predicate<T>::value,
|
||||
T,
|
||||
typename first_of<Predicate, Ts...>::type
|
||||
typename first_of<Predicate, Default, Ts...>::type
|
||||
>::type;
|
||||
};
|
||||
template <template<class> class Predicate, class... T> using first_of_t = typename first_of<Predicate, T...>::type;
|
||||
template <template<class> class Predicate, class Default, class... T> using first_of_t = typename first_of<Predicate, Default, T...>::type;
|
||||
|
||||
// Counts the number of types in the template parameter pack matching the predicate
|
||||
template <template<typename> class Predicate, typename... Ts> struct count_t;
|
||||
|
||||
@@ -802,34 +802,47 @@ protected:
|
||||
|
||||
static void releasebuffer(PyObject *, Py_buffer *view) { delete (buffer_info *) view->internal; }
|
||||
};
|
||||
|
||||
template <template<typename> class Predicate, typename... BaseTypes> struct class_selector;
|
||||
template <template<typename> class Predicate, typename Base, typename... Bases>
|
||||
struct class_selector<Predicate, Base, Bases...> {
|
||||
static inline void set_bases(detail::type_record &record) {
|
||||
if (Predicate<Base>::value) record.base_type = &typeid(Base);
|
||||
else class_selector<Predicate, Bases...>::set_bases(record);
|
||||
}
|
||||
};
|
||||
template <template<typename> class Predicate>
|
||||
struct class_selector<Predicate> {
|
||||
static inline void set_bases(detail::type_record &) {}
|
||||
};
|
||||
|
||||
NAMESPACE_END(detail)
|
||||
|
||||
template <typename type_, typename... options>
|
||||
class class_ : public detail::generic_type {
|
||||
template <typename T> using is_holder = detail::is_holder_type<type_, T>;
|
||||
template <typename T> using is_subtype = detail::bool_constant<std::is_base_of<type_, T>::value && !std::is_same<T, type_>::value>;
|
||||
template <typename T> using is_base_class = detail::bool_constant<std::is_base_of<T, type_>::value && !std::is_same<T, type_>::value>;
|
||||
template <typename T> using is_valid_class_option =
|
||||
detail::bool_constant<
|
||||
is_holder<T>::value ||
|
||||
is_subtype<T>::value
|
||||
is_subtype<T>::value ||
|
||||
is_base_class<T>::value
|
||||
>;
|
||||
|
||||
using extracted_holder_t = typename detail::first_of_t<is_holder, options...>;
|
||||
|
||||
public:
|
||||
using type = type_;
|
||||
using type_alias = detail::first_of_t<is_subtype, options...>;
|
||||
using type_alias = detail::first_of_t<is_subtype, void, options...>;
|
||||
constexpr static bool has_alias = !std::is_void<type_alias>::value;
|
||||
using holder_type = typename std::conditional<
|
||||
std::is_void<extracted_holder_t>::value,
|
||||
std::unique_ptr<type>,
|
||||
extracted_holder_t
|
||||
>::type;
|
||||
using holder_type = detail::first_of_t<is_holder, std::unique_ptr<type>, options...>;
|
||||
using instance_type = detail::instance<type, holder_type>;
|
||||
|
||||
static_assert(detail::all_of_t<is_valid_class_option, options...>::value,
|
||||
"Unknown/invalid class_ template parameters provided");
|
||||
|
||||
static_assert(detail::count_t<is_base_class, options...>::value <= 1,
|
||||
"Invalid class_ base types: multiple inheritance is not supported");
|
||||
|
||||
PYBIND11_OBJECT(class_, detail::generic_type, PyType_Check)
|
||||
|
||||
template <typename... Extra>
|
||||
@@ -843,6 +856,8 @@ public:
|
||||
record.init_holder = init_holder;
|
||||
record.dealloc = dealloc;
|
||||
|
||||
detail::class_selector<is_base_class, options...>::set_bases(record);
|
||||
|
||||
/* Process optional arguments, if any */
|
||||
detail::process_attributes<Extra...>::init(extra..., &record);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user