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`
This commit is contained in:
Sergei Izmailov 2023-09-07 21:57:39 +09:00 committed by GitHub
parent 4a2f7e4681
commit c83605936b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 29 additions and 4 deletions

View File

@ -2434,7 +2434,7 @@ iterator make_iterator_impl(Iterator first, Sentinel last, Extra &&...extra) {
Policy); Policy);
} }
return cast(state{first, last, true}); return cast(state{std::forward<Iterator>(first), std::forward<Sentinel>(last), true});
} }
PYBIND11_NAMESPACE_END(detail) PYBIND11_NAMESPACE_END(detail)
@ -2451,7 +2451,9 @@ iterator make_iterator(Iterator first, Sentinel last, Extra &&...extra) {
Iterator, Iterator,
Sentinel, Sentinel,
ValueType, ValueType,
Extra...>(first, last, std::forward<Extra>(extra)...); Extra...>(std::forward<Iterator>(first),
std::forward<Sentinel>(last),
std::forward<Extra>(extra)...);
} }
/// Makes a python iterator over the keys (`.first`) of a iterator over pairs from a /// 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) {
Iterator, Iterator,
Sentinel, Sentinel,
KeyType, KeyType,
Extra...>(first, last, std::forward<Extra>(extra)...); Extra...>(std::forward<Iterator>(first),
std::forward<Sentinel>(last),
std::forward<Extra>(extra)...);
} }
/// Makes a python iterator over the values (`.second`) of a iterator over pairs from a /// 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) {
Iterator, Iterator,
Sentinel, Sentinel,
ValueType, ValueType,
Extra...>(first, last, std::forward<Extra>(extra)...); Extra...>(std::forward<Iterator>(first),
std::forward<Sentinel>(last),
std::forward<Extra>(extra)...);
} }
/// Makes an iterator over values of an stl container or other container supporting /// Makes an iterator over values of an stl container or other container supporting

View File

@ -28,6 +28,13 @@ class NonZeroIterator {
public: public:
explicit NonZeroIterator(const T *ptr) : ptr_(ptr) {} explicit NonZeroIterator(const T *ptr) : ptr_(ptr) {}
// Make the iterator non-copyable and movable
NonZeroIterator(const NonZeroIterator &) = delete;
NonZeroIterator(NonZeroIterator &&) noexcept = default;
NonZeroIterator &operator=(const NonZeroIterator &) = delete;
NonZeroIterator &operator=(NonZeroIterator &&) noexcept = default;
const T &operator*() const { return *ptr_; } const T &operator*() const { return *ptr_; }
NonZeroIterator &operator++() { NonZeroIterator &operator++() {
++ptr_; ++ptr_;
@ -78,6 +85,7 @@ private:
int value_; int value_;
}; };
using NonCopyableIntPair = std::pair<NonCopyableInt, NonCopyableInt>; using NonCopyableIntPair = std::pair<NonCopyableInt, NonCopyableInt>;
PYBIND11_MAKE_OPAQUE(std::vector<NonCopyableInt>); PYBIND11_MAKE_OPAQUE(std::vector<NonCopyableInt>);
PYBIND11_MAKE_OPAQUE(std::vector<NonCopyableIntPair>); PYBIND11_MAKE_OPAQUE(std::vector<NonCopyableIntPair>);
@ -375,6 +383,17 @@ TEST_SUBMODULE(sequences_and_iterators, m) {
private: private:
std::vector<std::pair<int, int>> data_; std::vector<std::pair<int, int>> data_;
}; };
{
// #4383 : Make sure `py::make_*iterator` functions work with move-only iterators
using iterator_t = NonZeroIterator<std::pair<int, int>>;
static_assert(std::is_move_assignable<iterator_t>::value, "");
static_assert(std::is_move_constructible<iterator_t>::value, "");
static_assert(!std::is_copy_assignable<iterator_t>::value, "");
static_assert(!std::is_copy_constructible<iterator_t>::value, "");
}
py::class_<IntPairs>(m, "IntPairs") py::class_<IntPairs>(m, "IntPairs")
.def(py::init<std::vector<std::pair<int, int>>>()) .def(py::init<std::vector<std::pair<int, int>>>())
.def( .def(