Skip to content

Commit f33465c

Browse files
authored
Default to rv_policy::move when binding in-place operators (#803)
1 parent 030a9ca commit f33465c

File tree

3 files changed

+14
-2
lines changed

3 files changed

+14
-2
lines changed

docs/changelog.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@ Version TBD (unreleased)
4343
of storing a dangling C++ iterator reference in the returned Python
4444
iterator object. (PR `#788 <https://github.com/wjakob/nanobind/pull/788>`__)
4545

46+
- Bindings for augmented assignment operators (as generated, for example, by
47+
``.def(nb::self += nb::self)``) now return the same object in Python in the
48+
typical case where the C++ operator returns a reference to ``*this``.
49+
Previously, after ``a += b``, ``a`` would be replaced with a copy.
50+
(PR `#803 <https://github.com/wjakob/nanobind/pull/803>`__)
51+
4652
Version 2.2.0 (October 3, 2024)
4753
-------------------------------
4854

include/nanobind/operators.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,25 +45,27 @@ template <op_id id, op_type ot, typename L, typename R> struct op_ {
4545
using Lt = std::conditional_t<std::is_same_v<L, self_t>, Type, L>;
4646
using Rt = std::conditional_t<std::is_same_v<R, self_t>, Type, R>;
4747
using Op = op_impl<id, ot, Type, Lt, Rt>;
48-
cl.def(Op::name(), &Op::execute, is_operator(), extra...);
48+
cl.def(Op::name(), &Op::execute, is_operator(), Op::default_policy, extra...);
4949
}
5050

5151
template <typename Class, typename... Extra> void execute_cast(Class &cl, const Extra&... extra) const {
5252
using Type = typename Class::Type;
5353
using Lt = std::conditional_t<std::is_same_v<L, self_t>, Type, L>;
5454
using Rt = std::conditional_t<std::is_same_v<R, self_t>, Type, R>;
5555
using Op = op_impl<id, ot, Type, Lt, Rt>;
56-
cl.def(Op::name(), &Op::execute_cast, is_operator(), extra...);
56+
cl.def(Op::name(), &Op::execute_cast, is_operator(), Op::default_policy, extra...);
5757
}
5858
};
5959

6060
#define NB_BINARY_OPERATOR(id, rid, op, expr) \
6161
template <typename B, typename L, typename R> struct op_impl<op_##id, op_l, B, L, R> { \
62+
static constexpr rv_policy default_policy = rv_policy::automatic; \
6263
static char const* name() { return "__" #id "__"; } \
6364
static auto execute(const L &l, const R &r) -> decltype(expr) { return (expr); } \
6465
static B execute_cast(const L &l, const R &r) { return B(expr); } \
6566
}; \
6667
template <typename B, typename L, typename R> struct op_impl<op_##id, op_r, B, L, R> { \
68+
static constexpr rv_policy default_policy = rv_policy::automatic; \
6769
static char const* name() { return "__" #rid "__"; } \
6870
static auto execute(const R &r, const L &l) -> decltype(expr) { return (expr); } \
6971
static B execute_cast(const R &r, const L &l) { return B(expr); } \
@@ -80,6 +82,7 @@ template <typename T> op_<op_##id, op_r, T, self_t> op(const T &, const self_t &
8082

8183
#define NB_INPLACE_OPERATOR(id, op, expr) \
8284
template <typename B, typename L, typename R> struct op_impl<op_##id, op_l, B, L, R> { \
85+
static constexpr rv_policy default_policy = rv_policy::move; \
8386
static char const* name() { return "__" #id "__"; } \
8487
static auto execute(L &l, const R &r) -> decltype(expr) { return expr; } \
8588
static B execute_cast(L &l, const R &r) { return B(expr); } \
@@ -90,6 +93,7 @@ template <typename T> op_<op_##id, op_l, self_t, T> op(const self_t &, const T &
9093

9194
#define NB_UNARY_OPERATOR(id, op, expr) \
9295
template <typename B, typename L> struct op_impl<op_##id, op_u, B, L, undefined_t> { \
96+
static constexpr rv_policy default_policy = rv_policy::automatic; \
9397
static char const* name() { return "__" #id "__"; } \
9498
static auto execute(const L &l) -> decltype(expr) { return expr; } \
9599
static B execute_cast(const L &l) { return B(expr); } \

tests/test_classes.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,9 @@ def test14_operators():
325325
assert repr(a - b) == "3"
326326
assert "unsupported operand type" in str(excinfo.value)
327327
assert repr(a - 2) == "-1"
328+
a_before = id(a)
328329
a += b
330+
assert id(a) == a_before
329331
assert repr(a) == "3"
330332
assert repr(b) == "2"
331333

0 commit comments

Comments
 (0)