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).
This commit is contained in:
Jason Rhinelander 2017-01-20 00:59:26 -05:00 committed by Wenzel Jakob
parent fd7517037b
commit 546f6fce1a
2 changed files with 13 additions and 4 deletions

View File

@ -1097,6 +1097,17 @@ template <typename type> using cast_is_temporary_value_reference = bool_constant
!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)) {

View File

@ -135,10 +135,8 @@ protected:
? &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),