From b212f6c416654ca4e6676487ccea6104c0f93338 Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Sat, 10 Sep 2016 16:00:50 +0900 Subject: [PATCH] parameterize iterators by return value policy (fixes #388) --- include/pybind11/pybind11.h | 26 +++++++++++++++----------- include/pybind11/stl_bind.h | 10 ++++++---- tests/test_issues.cpp | 5 +++++ tests/test_issues.py | 9 +++++++++ 4 files changed, 35 insertions(+), 15 deletions(-) diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index 4a50b335..550c41dc 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -1175,7 +1175,7 @@ PYBIND11_NOINLINE inline void keep_alive_impl(int Nurse, int Patient, handle arg keep_alive_impl(nurse, patient); } -template +template struct iterator_state { Iterator it; Sentinel end; @@ -1187,12 +1187,13 @@ NAMESPACE_END(detail) template detail::init init() { return detail::init(); } template detail::init_alias init_alias() { return detail::init_alias(); } -template ()), typename... Extra> iterator make_iterator(Iterator first, Sentinel last, Extra &&... extra) { - typedef detail::iterator_state state; + typedef detail::iterator_state state; if (!detail::get_type_info(typeid(state))) { class_(handle(), "iterator") @@ -1205,18 +1206,19 @@ iterator make_iterator(Iterator first, Sentinel last, Extra &&... extra) { if (s.it == s.end) throw stop_iteration(); return *s.it; - }, return_value_policy::reference_internal, std::forward(extra)...); + }, std::forward(extra)..., Policy); } return (iterator) cast(state { first, last, true }); } -template ()).first), typename... Extra> iterator make_key_iterator(Iterator first, Sentinel last, Extra &&... extra) { - typedef detail::iterator_state state; + typedef detail::iterator_state state; if (!detail::get_type_info(typeid(state))) { class_(handle(), "iterator") @@ -1229,18 +1231,20 @@ iterator make_key_iterator(Iterator first, Sentinel last, Extra &&... extra) { if (s.it == s.end) throw stop_iteration(); return (*s.it).first; - }, return_value_policy::reference_internal, std::forward(extra)...); + }, std::forward(extra)..., Policy); } return (iterator) cast(state { first, last, true }); } -template iterator make_iterator(Type &value, Extra&&... extra) { - return make_iterator(std::begin(value), std::end(value), extra...); +template iterator make_iterator(Type &value, Extra&&... extra) { + return make_iterator(std::begin(value), std::end(value), extra...); } -template iterator make_key_iterator(Type &value, Extra&&... extra) { - return make_key_iterator(std::begin(value), std::end(value), extra...); +template iterator make_key_iterator(Type &value, Extra&&... extra) { + return make_key_iterator(std::begin(value), std::end(value), extra...); } template void implicitly_convertible() { diff --git a/include/pybind11/stl_bind.h b/include/pybind11/stl_bind.h index e093e422..efdb3f99 100644 --- a/include/pybind11/stl_bind.h +++ b/include/pybind11/stl_bind.h @@ -246,10 +246,12 @@ pybind11::class_ bind_vector(pybind11::module &m, std::stri cl.def("__len__", &Vector::size); cl.def("__iter__", - [](Vector &v) { - return pybind11::make_iterator(v.begin(), v.end()); - }, - pybind11::keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */ + [](Vector &v) { + return pybind11::make_iterator< + return_value_policy::reference_internal, ItType, ItType, T>( + v.begin(), v.end()); + }, + pybind11::keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */ ); /// Slicing protocol diff --git a/tests/test_issues.cpp b/tests/test_issues.cpp index 3fc8aeb6..f2d9a51a 100644 --- a/tests/test_issues.cpp +++ b/tests/test_issues.cpp @@ -233,6 +233,11 @@ void init_issues(py::module &m) { .def(py::self + py::self) .def("__add__", [](const OpTest2& c2, const OpTest1& c1) { return c2 + c1; }) .def("__radd__", [](const OpTest2& c2, const OpTest1& c1) { return c2 + c1; }); + + // Issue 388: Can't make iterators via make_iterator() with different r/v policies + static std::vector list = { 1, 2, 3 }; + m2.def("make_iterator_1", []() { return py::make_iterator(list); }); + m2.def("make_iterator_2", []() { return py::make_iterator(list); }); } // MSVC workaround: trying to use a lambda here crashes MSCV diff --git a/tests/test_issues.py b/tests/test_issues.py index b4b8f95f..ad3d39d5 100644 --- a/tests/test_issues.py +++ b/tests/test_issues.py @@ -170,3 +170,12 @@ def test_operators_notimplemented(capture): Add OpTest2 with OpTest2 Add OpTest2 with OpTest1 Add OpTest2 with OpTest1""" + +def test_iterator_rvpolicy(): + """ Issue 388: Can't make iterators via make_iterator() with different r/v policies """ + from pybind11_tests.issues import make_iterator_1 + from pybind11_tests.issues import make_iterator_2 + + assert list(make_iterator_1()) == [1, 2, 3] + assert list(make_iterator_2()) == [1, 2, 3] + assert(type(make_iterator_1()) != type(make_iterator_2()))