@@ -863,14 +863,8 @@ template <typename type> using cast_is_temporary_value_reference = bool_constant
863
863
!std::is_base_of<type_caster_generic, make_caster<type>>::value
864
864
>;
865
865
866
-
867
- NAMESPACE_END (detail)
868
-
869
- template <typename T> T cast(const handle &handle) {
870
- using type_caster = detail::make_caster<T>;
871
- static_assert (!detail::cast_is_temporary_value_reference<T>::value,
872
- " Unable to cast type to reference: value is local to type caster" );
873
- type_caster conv;
866
+ // Basic python -> C++ casting; throws if casting fails
867
+ template <typename TypeCaster> TypeCaster &load_type (TypeCaster &conv, const handle &handle) {
874
868
if (!conv.load (handle, true )) {
875
869
#if defined(NDEBUG)
876
870
throw cast_error (" Unable to cast Python instance to C++ type (compile in debug mode for details)" );
@@ -879,7 +873,22 @@ template <typename T> T cast(const handle &handle) {
879
873
(std::string) handle.get_type ().str () + " to C++ type '" + type_id<T>() + " ''" );
880
874
#endif
881
875
}
882
- return conv.operator typename type_caster::template cast_op_type<T>();
876
+ return conv;
877
+ }
878
+ // Wrapper around the above that also constructs and returns a type_caster
879
+ template <typename T> make_caster<T> load_type (const handle &handle) {
880
+ make_caster<T> conv;
881
+ load_type (conv, handle);
882
+ return conv;
883
+ }
884
+
885
+ NAMESPACE_END (detail)
886
+
887
+ template <typename T> T cast(const handle &handle) {
888
+ static_assert (!detail::cast_is_temporary_value_reference<T>::value,
889
+ " Unable to cast type to reference: value is local to type caster" );
890
+ using type_caster = detail::make_caster<T>;
891
+ return detail::load_type<T>(handle).operator typename type_caster::template cast_op_type<T>();
883
892
}
884
893
885
894
template <typename T> object cast (const T &value,
@@ -896,7 +905,7 @@ template <typename T> T handle::cast() const { return pybind11::cast<T>(*this);
896
905
template <> inline void handle::cast () const { return ; }
897
906
898
907
template <typename T>
899
- typename std::enable_if <detail::move_always<T>::value || detail::move_if_unreferenced<T>::value, T>::type move (object &&obj) {
908
+ detail:: enable_if_t <detail::move_always<T>::value || detail::move_if_unreferenced<T>::value, T> move (object &&obj) {
900
909
if (obj.ref_count () > 1 )
901
910
#if defined(NDEBUG)
902
911
throw cast_error (" Unable to cast Python instance to C++ rvalue: instance has multiple references"
@@ -906,18 +915,8 @@ typename std::enable_if<detail::move_always<T>::value || detail::move_if_unrefer
906
915
" instance to C++ " + type_id<T>() + " instance: instance has multiple references" );
907
916
#endif
908
917
909
- typedef detail::type_caster<T> type_caster;
910
- type_caster conv;
911
- if (!conv.load (obj, true ))
912
- #if defined(NDEBUG)
913
- throw cast_error (" Unable to cast Python instance to C++ type (compile in debug mode for details)" );
914
- #else
915
- throw cast_error (" Unable to cast Python instance of type " +
916
- (std::string) obj.get_type ().str () + " to C++ type '" + type_id<T>() + " ''" );
917
- #endif
918
-
919
918
// Move into a temporary and return that, because the reference may be a local value of `conv`
920
- T ret = std::move (conv .operator T&());
919
+ T ret = std::move (detail::load_type<T>(obj) .operator T&());
921
920
return ret;
922
921
}
923
922
@@ -926,16 +925,16 @@ typename std::enable_if<detail::move_always<T>::value || detail::move_if_unrefer
926
925
// object has multiple references, but trying to copy will fail to compile.
927
926
// - If both movable and copyable, check ref count: if 1, move; otherwise copy
928
927
// - Otherwise (not movable), copy.
929
- template <typename T> typename std::enable_if <detail::move_always<T>::value, T>::type cast (object &&object) {
928
+ template <typename T> detail:: enable_if_t <detail::move_always<T>::value, T> cast (object &&object) {
930
929
return move<T>(std::move (object));
931
930
}
932
- template <typename T> typename std::enable_if <detail::move_if_unreferenced<T>::value, T>::type cast (object &&object) {
931
+ template <typename T> detail:: enable_if_t <detail::move_if_unreferenced<T>::value, T> cast (object &&object) {
933
932
if (object.ref_count () > 1 )
934
933
return cast<T>(object);
935
934
else
936
935
return move<T>(std::move (object));
937
936
}
938
- template <typename T> typename std::enable_if <detail::move_never<T>::value, T>::type cast (object &&object) {
937
+ template <typename T> detail:: enable_if_t <detail::move_never<T>::value, T> cast (object &&object) {
939
938
return cast<T>(object);
940
939
}
941
940
@@ -944,6 +943,30 @@ template <typename T> T object::cast() && { return pybind11::cast<T>(std::move(*
944
943
template <> inline void object::cast () const & { return ; }
945
944
template <> inline void object::cast () && { return ; }
946
945
946
+ NAMESPACE_BEGIN (detail)
947
+
948
+ struct overload_unused {}; // Placeholder type for the unneeded (and dead code) static variable in the OVERLOAD_INT macro
949
+ template <typename ret_type> using overload_caster_t = conditional_t <
950
+ cast_is_temporary_value_reference<ret_type>::value, make_caster<ret_type>, overload_unused>;
951
+
952
+ // Trampoline use: for reference/pointer types to value-converted values, we do a value cast, then
953
+ // store the result in the given variable. For other types, this is a no-op.
954
+ template <typename T> enable_if_t <cast_is_temporary_value_reference<T>::value, T> cast_ref (object &&o, make_caster<T> &caster) {
955
+ return load_type (caster, o).operator typename make_caster<T>::template cast_op_type<T>();
956
+ }
957
+ template <typename T> enable_if_t <!cast_is_temporary_value_reference<T>::value, T> cast_ref (object &&, overload_unused &) {
958
+ pybind11_fail (" Internal error: cast_ref fallback invoked" ); }
959
+
960
+ // Trampoline use: Having a pybind11::cast with an invalid reference type is going to static_assert, even
961
+ // though if it's in dead code, so we provide a "trampoline" to pybind11::cast that only does anything in
962
+ // cases where pybind11::cast is valid.
963
+ template <typename T> enable_if_t <!cast_is_temporary_value_reference<T>::value, T> cast_safe (object &&o) {
964
+ return pybind11::cast<T>(std::move (o)); }
965
+ template <typename T> enable_if_t <cast_is_temporary_value_reference<T>::value, T> cast_safe (object &&) {
966
+ pybind11_fail (" Internal error: cast_safe fallback invoked" ); }
967
+ template <> inline void cast_safe<void >(object &&) {}
968
+
969
+ NAMESPACE_END (detail)
947
970
948
971
949
972
template <return_value_policy policy = return_value_policy::automatic_reference,
0 commit comments