@@ -44,8 +44,6 @@ NAMESPACE_BEGIN(pybind11)
44
44
45
45
// / Wraps an arbitrary C++ function/method/lambda function/.. into a callable Python object
46
46
class cpp_function : public function {
47
- private:
48
- template <typename Extra> using is_method_annotation = detail::is_instantiation<is_method, Extra>;
49
47
public:
50
48
cpp_function () { }
51
49
@@ -68,22 +66,17 @@ class cpp_function : public function {
68
66
(FuncType *) nullptr , extra...);
69
67
}
70
68
71
- // / Construct a cpp_function from a class method (non-const)
72
69
template <typename Return, typename Class, typename ... Arg, typename ... Extra>
73
70
cpp_function (Return (Class::*f)(Arg...), const Extra&... extra) {
74
- using ClassArg = typename detail::exactly_one_t <is_method_annotation, is_method<Class>, Extra...>
75
- ::template BindClass<Class>;
76
- initialize ([f](ClassArg *c, Arg... args) -> Return { return (c->*f)(args...); },
77
- (Return (*) (ClassArg *, Arg...)) nullptr , extra...);
71
+ initialize ([f](Class *c, Arg... args) -> Return { return (c->*f)(args...); },
72
+ (Return (*) (Class *, Arg...)) nullptr , extra...);
78
73
}
79
74
80
75
// / Construct a cpp_function from a class method (const)
81
76
template <typename Return, typename Class, typename ... Arg, typename ... Extra>
82
77
cpp_function (Return (Class::*f)(Arg...) const , const Extra&... extra) {
83
- using ClassArg = typename detail::exactly_one_t <is_method_annotation, is_method<Class>, Extra...>
84
- ::template BindClass<Class>;
85
- initialize ([f](const ClassArg *c, Arg... args) -> Return { return (c->*f)(args...); },
86
- (Return (*)(const ClassArg *, Arg ...)) nullptr , extra...);
78
+ initialize ([f](const Class *c, Arg... args) -> Return { return (c->*f)(args...); },
79
+ (Return (*)(const Class *, Arg ...)) nullptr , extra...);
87
80
}
88
81
89
82
// / Return the function name
@@ -912,13 +905,40 @@ void call_operator_delete(T *p) { T::operator delete(p); }
912
905
913
906
inline void call_operator_delete (void *p) { ::operator delete (p); }
914
907
908
+ // Wrapper around cpp_function that binds a method pointer of a base class with a derived class
909
+ // argument, as opposed to calling cpp_function directly which always uses the inferred class. For
910
+ // any other type of argument, this is identical to cpp_function.
911
+ template <typename Derived, typename Func, typename SFINAE = void > struct method_adaptor_impl {
912
+ template <typename ... Args> static cpp_function adapt (Args &&... args) { return {std::forward<Args>(args)...}; }
913
+ };
914
+ template <typename Derived, typename Return, typename Class, typename ... Arg>
915
+ struct method_adaptor_impl <Derived, Return (Class::*)(Arg...), enable_if_t <is_strict_base_of<Class, Derived>::value>> {
916
+ template <typename ... Extra> static cpp_function adapt (Return (Class::*f)(Arg...), const Extra&... extra) {
917
+ return {[f](Derived *c, Arg... args) -> Return { return (c->*f)(args...); }, extra...};
918
+ }
919
+ };
920
+ template <typename Derived, typename Return, typename Class, typename ... Arg>
921
+ struct method_adaptor_impl <Derived, Return (Class::*)(Arg...) const , enable_if_t <is_strict_base_of<Class, Derived>::value>> {
922
+ template <typename ... Extra> static cpp_function adapt (Return (Class::*f)(Arg...) const , const Extra&... extra) {
923
+ return {[f](const Derived *c, Arg... args) -> Return { return (c->*f)(args...); }, extra...};
924
+ }
925
+ };
926
+
915
927
NAMESPACE_END (detail)
916
928
929
+ // / Returns a cpp_function around the given method or function; if given a method pointer to a base
930
+ // / class of Derived, this results in a lambda that takes a `Derived *` as first argument, rather
931
+ // / than the usual deduced `Base *` type.
932
+ template <typename Derived, typename Func, typename... Extra> cpp_function method_adaptor(Func &&f, const Extra&... extra) {
933
+ return detail::method_adaptor_impl<Derived, detail::remove_cv_t <detail::remove_reference_t <Func>>>::adapt (
934
+ std::forward<Func>(f), extra...);
935
+ }
936
+
917
937
template <typename type_, typename ... options>
918
938
class class_ : public detail ::generic_type {
919
939
template <typename T> using is_holder = detail::is_holder_type<type_, T>;
920
- template <typename T> using is_subtype = detail::bool_constant<std::is_base_of< type_, T>::value && !std::is_same<T, type_>::value >;
921
- template <typename T> using is_base = detail::bool_constant<std::is_base_of< T, type_>::value && !std::is_same<T, type_>::value >;
940
+ template <typename T> using is_subtype = detail::is_strict_base_of< type_, T>;
941
+ template <typename T> using is_base = detail::is_strict_base_of< T, type_>;
922
942
// struct instead of using here to help MSVC:
923
943
template <typename T> struct is_valid_class_option :
924
944
detail::any_of<is_holder<T>, is_subtype<T>, is_base<T>> {};
@@ -984,8 +1004,9 @@ class class_ : public detail::generic_type {
984
1004
985
1005
template <typename Func, typename ... Extra>
986
1006
class_ &def (const char *name_, Func&& f, const Extra&... extra) {
987
- cpp_function cf (std::forward<Func>(f), name (name_), is_method<type>(*this ),
988
- sibling (getattr (*this , name_, none ())), extra...);
1007
+ auto cf = method_adaptor<type>(
1008
+ std::forward<Func>(f), name (name_), is_method (*this ),
1009
+ sibling (getattr (*this , name_, none ())), extra...);
989
1010
attr (cf.name ()) = cf;
990
1011
return *this ;
991
1012
}
@@ -1048,18 +1069,18 @@ class class_ : public detail::generic_type {
1048
1069
1049
1070
template <typename C, typename D, typename ... Extra>
1050
1071
class_ &def_readwrite (const char *name, D C::*pm, const Extra&... extra) {
1051
- using BindC = typename is_method<type>::template BindClass<C>;
1052
- def_property (name,
1053
- [pm](const BindC &c) -> const D &{ return c.*pm; },
1054
- [pm](BindC &c, const D &value) { c.*pm = value; },
1055
- extra...);
1072
+ static_assert (std::is_base_of<C, type>::value, " def_readwrite() requires a class member (or base class member)" );
1073
+ cpp_function fget ([pm](const type &c) -> const D &{ return c.*pm; }, is_method (*this )),
1074
+ fset ([pm](type &c, const D &value) { c.*pm = value; }, is_method (*this ));
1075
+ def_property (name, fget, fset, return_value_policy::reference_internal, extra...);
1056
1076
return *this ;
1057
1077
}
1058
1078
1059
1079
template <typename C, typename D, typename ... Extra>
1060
1080
class_ &def_readonly (const char *name, const D C::*pm, const Extra& ...extra) {
1061
- using BindC = typename is_method<type>::template BindClass<C>;
1062
- def_property_readonly (name, [pm](const BindC &c) -> const D &{ return c.*pm; }, extra...);
1081
+ static_assert (std::is_base_of<C, type>::value, " def_readonly() requires a class member (or base class member)" );
1082
+ cpp_function fget ([pm](const type &c) -> const D &{ return c.*pm; }, is_method (*this ));
1083
+ def_property_readonly (name, fget, return_value_policy::reference_internal, extra...);
1063
1084
return *this ;
1064
1085
}
1065
1086
@@ -1081,7 +1102,8 @@ class class_ : public detail::generic_type {
1081
1102
// / Uses return_value_policy::reference_internal by default
1082
1103
template <typename Getter, typename ... Extra>
1083
1104
class_ &def_property_readonly (const char *name, const Getter &fget, const Extra& ...extra) {
1084
- return def_property_readonly (name, cpp_function (fget, is_method<type>(*this )), return_value_policy::reference_internal, extra...);
1105
+ return def_property_readonly (name, method_adaptor<type>(fget),
1106
+ return_value_policy::reference_internal, extra...);
1085
1107
}
1086
1108
1087
1109
// / Uses cpp_function's return_value_policy by default
@@ -1105,21 +1127,17 @@ class class_ : public detail::generic_type {
1105
1127
// / Uses return_value_policy::reference_internal by default
1106
1128
template <typename Getter, typename Setter, typename ... Extra>
1107
1129
class_ &def_property (const char *name, const Getter &fget, const Setter &fset, const Extra& ...extra) {
1108
- return def_property (name, fget,
1109
- cpp_function (fset, is_method<type>(*this ), return_value_policy::reference_internal),
1110
- extra...);
1130
+ return def_property (name, fget, method_adaptor<type>(fset, return_value_policy::reference_internal), extra...);
1111
1131
}
1112
1132
template <typename Getter, typename ... Extra>
1113
1133
class_ &def_property (const char *name, const Getter &fget, const cpp_function &fset, const Extra& ...extra) {
1114
- return def_property (name,
1115
- cpp_function (fget, is_method<type>(*this ), return_value_policy::reference_internal),
1116
- fset, extra...);
1134
+ return def_property (name, method_adaptor<type>(fget), fset, return_value_policy::reference_internal, extra...);
1117
1135
}
1118
1136
1119
1137
// / Uses cpp_function's return_value_policy by default
1120
1138
template <typename ... Extra>
1121
1139
class_ &def_property (const char *name, const cpp_function &fget, const cpp_function &fset, const Extra& ...extra) {
1122
- return def_property_static (name, fget, fset, is_method<type> (*this ), extra...);
1140
+ return def_property_static (name, fget, fset, is_method (*this ), extra...);
1123
1141
}
1124
1142
1125
1143
// / Uses return_value_policy::reference by default
0 commit comments