Add an ability to avoid forcing rvp::move
Eigen::Ref objects, when returned, are almost always returned as
rvalues; what's important is the data they reference, not the outer
shell, and so we want to be able to use `::copy`,
`::reference_internal`, etc. to refer to the data the Eigen::Ref
references (in the following commits), rather than the Eigen::Ref
instance itself.
This moves the policy override into a struct so that code that wants to
avoid it (or wants to provide some other Return-type-conditional
override) can create a specialization of
return_value_policy_override<Return> in order to override the override.
This lets an Eigen::Ref-returning function be bound with `rvp::copy`,
for example, to specify that the data should be copied into a new numpy
array rather than referenced, or `rvp::reference_internal` to indicate
that it should be referenced, but a keep-alive used (actually, we used
the array's `base` rather than a py::keep_alive in such a case, but it
accomplishes the same thing).
diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h
index 6cb02fd..b7128d1 100644
--- a/include/pybind11/cast.h
+++ b/include/pybind11/cast.h
@@ -1097,6 +1097,17 @@
!std::is_base_of<type_caster_generic, make_caster<type>>::value
>;
+// When a value returned from a C++ function is being cast back to Python, we almost always want to
+// force `policy = move`, regardless of the return value policy the function/method was declared
+// with. Some classes (most notably Eigen::Ref and related) need to avoid this, and so can do so by
+// specializing this struct.
+template <typename Return, typename SFINAE = void> struct return_value_policy_override {
+ static return_value_policy policy(return_value_policy p) {
+ return !std::is_lvalue_reference<Return>::value && !std::is_pointer<Return>::value
+ ? return_value_policy::move : p;
+ }
+};
+
// Basic python -> C++ casting; throws if casting fails
template <typename T, typename SFINAE> type_caster<T, SFINAE> &load_type(type_caster<T, SFINAE> &conv, const handle &handle) {
if (!conv.load(handle, true)) {
diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h
index ec3a5b0..9731433 100644
--- a/include/pybind11/pybind11.h
+++ b/include/pybind11/pybind11.h
@@ -135,10 +135,8 @@
? &call.func.data : call.func.data[0]);
capture *cap = const_cast<capture *>(reinterpret_cast<const capture *>(data));
- /* Override policy for rvalues -- always move */
- constexpr auto is_rvalue = !std::is_pointer<Return>::value
- && !std::is_lvalue_reference<Return>::value;
- const auto policy = is_rvalue ? return_value_policy::move : call.func.policy;
+ /* Override policy for rvalues -- usually to enforce rvp::move on an rvalue */
+ const auto policy = detail::return_value_policy_override<Return>::policy(call.func.policy);
/* Perform the function call */
handle result = cast_out::cast(args_converter.template call<Return>(cap->f),