mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-25 14:45:12 +00:00
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:
parent
fd7517037b
commit
546f6fce1a
@ -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)) {
|
||||
|
@ -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),
|
||||
|
Loading…
Reference in New Issue
Block a user