Skip to content

Commit c836059

Browse files
authored
feature: Support move-only iterators in py::make_*iterator (#4834)
* feature: Support move-only iterators in `py::make_*iterator` * fix: Missing static assertion message * fixup: Missing `explicit` in single argument constructors * fix: Simplify tests: make existing iterator move-only * fix: Missing `noexcept`
1 parent 4a2f7e4 commit c836059

File tree

2 files changed

+29
-4
lines changed

2 files changed

+29
-4
lines changed

include/pybind11/pybind11.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2434,7 +2434,7 @@ iterator make_iterator_impl(Iterator first, Sentinel last, Extra &&...extra) {
24342434
Policy);
24352435
}
24362436

2437-
return cast(state{first, last, true});
2437+
return cast(state{std::forward<Iterator>(first), std::forward<Sentinel>(last), true});
24382438
}
24392439

24402440
PYBIND11_NAMESPACE_END(detail)
@@ -2451,7 +2451,9 @@ iterator make_iterator(Iterator first, Sentinel last, Extra &&...extra) {
24512451
Iterator,
24522452
Sentinel,
24532453
ValueType,
2454-
Extra...>(first, last, std::forward<Extra>(extra)...);
2454+
Extra...>(std::forward<Iterator>(first),
2455+
std::forward<Sentinel>(last),
2456+
std::forward<Extra>(extra)...);
24552457
}
24562458

24572459
/// Makes a python iterator over the keys (`.first`) of a iterator over pairs from a
@@ -2467,7 +2469,9 @@ iterator make_key_iterator(Iterator first, Sentinel last, Extra &&...extra) {
24672469
Iterator,
24682470
Sentinel,
24692471
KeyType,
2470-
Extra...>(first, last, std::forward<Extra>(extra)...);
2472+
Extra...>(std::forward<Iterator>(first),
2473+
std::forward<Sentinel>(last),
2474+
std::forward<Extra>(extra)...);
24712475
}
24722476

24732477
/// Makes a python iterator over the values (`.second`) of a iterator over pairs from a
@@ -2483,7 +2487,9 @@ iterator make_value_iterator(Iterator first, Sentinel last, Extra &&...extra) {
24832487
Iterator,
24842488
Sentinel,
24852489
ValueType,
2486-
Extra...>(first, last, std::forward<Extra>(extra)...);
2490+
Extra...>(std::forward<Iterator>(first),
2491+
std::forward<Sentinel>(last),
2492+
std::forward<Extra>(extra)...);
24872493
}
24882494

24892495
/// Makes an iterator over values of an stl container or other container supporting

tests/test_sequences_and_iterators.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@ class NonZeroIterator {
2828

2929
public:
3030
explicit NonZeroIterator(const T *ptr) : ptr_(ptr) {}
31+
32+
// Make the iterator non-copyable and movable
33+
NonZeroIterator(const NonZeroIterator &) = delete;
34+
NonZeroIterator(NonZeroIterator &&) noexcept = default;
35+
NonZeroIterator &operator=(const NonZeroIterator &) = delete;
36+
NonZeroIterator &operator=(NonZeroIterator &&) noexcept = default;
37+
3138
const T &operator*() const { return *ptr_; }
3239
NonZeroIterator &operator++() {
3340
++ptr_;
@@ -78,6 +85,7 @@ class NonCopyableInt {
7885
int value_;
7986
};
8087
using NonCopyableIntPair = std::pair<NonCopyableInt, NonCopyableInt>;
88+
8189
PYBIND11_MAKE_OPAQUE(std::vector<NonCopyableInt>);
8290
PYBIND11_MAKE_OPAQUE(std::vector<NonCopyableIntPair>);
8391

@@ -375,6 +383,17 @@ TEST_SUBMODULE(sequences_and_iterators, m) {
375383
private:
376384
std::vector<std::pair<int, int>> data_;
377385
};
386+
387+
{
388+
// #4383 : Make sure `py::make_*iterator` functions work with move-only iterators
389+
using iterator_t = NonZeroIterator<std::pair<int, int>>;
390+
391+
static_assert(std::is_move_assignable<iterator_t>::value, "");
392+
static_assert(std::is_move_constructible<iterator_t>::value, "");
393+
static_assert(!std::is_copy_assignable<iterator_t>::value, "");
394+
static_assert(!std::is_copy_constructible<iterator_t>::value, "");
395+
}
396+
378397
py::class_<IntPairs>(m, "IntPairs")
379398
.def(py::init<std::vector<std::pair<int, int>>>())
380399
.def(

0 commit comments

Comments
 (0)