Skip to content

Commit eab5682

Browse files
committed
fix: regression in #3271
1 parent bf1e50b commit eab5682

File tree

3 files changed

+25
-8
lines changed

3 files changed

+25
-8
lines changed

include/pybind11/pybind11.h

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1966,27 +1966,29 @@ struct iterator_state {
19661966
};
19671967

19681968
// Note: these helpers take the iterator by non-const reference because some
1969-
// iterators in the wild can't be dereferenced when const.
1970-
template <typename Iterator>
1969+
// iterators in the wild can't be dereferenced when const. C++ needs the extra parens in decltype
1970+
// to enforce an lvalue. The & after Iterator is required for MSVC < 16.9. ResultType cannot be
1971+
// reused for result_type due to bugs in ICC, NVCC, and PGI. See #3293.
1972+
template <typename Iterator, typename ResultType = decltype((*std::declval<Iterator &>()))>
19711973
struct iterator_access {
1972-
using result_type = decltype((*std::declval<Iterator>()));
1973-
// NOLINTNEXTLINE(readability-const-return-type) // PR #3263
1974+
using result_type = decltype((*std::declval<Iterator &>()));
1975+
// NOLINTNEXTLINE(readability-const-return-type)
19741976
result_type operator()(Iterator &it) const {
19751977
return *it;
19761978
}
19771979
};
19781980

1979-
template <typename Iterator>
1981+
template <typename Iterator, typename ResultType = decltype(((*std::declval<Iterator &>()).first)) >
19801982
struct iterator_key_access {
1981-
using result_type = decltype(((*std::declval<Iterator>()).first));
1983+
using result_type = decltype(((*std::declval<Iterator &>()).first));
19821984
result_type operator()(Iterator &it) const {
19831985
return (*it).first;
19841986
}
19851987
};
19861988

1987-
template <typename Iterator>
1989+
template <typename Iterator, typename ResultType = decltype(((*std::declval<Iterator &>()).second))>
19881990
struct iterator_value_access {
1989-
using result_type = decltype(((*std::declval<Iterator>()).second));
1991+
using result_type = decltype(((*std::declval<Iterator &>()).second));
19901992
result_type operator()(Iterator &it) const {
19911993
return (*it).second;
19921994
}

tests/test_sequences_and_iterators.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,20 @@ TEST_SUBMODULE(sequences_and_iterators, m) {
346346
return py::make_key_iterator(self);
347347
}, py::keep_alive<0, 1>())
348348

349+
// test iterator with keep_alive (doesn't work so not used at runtime, but tests compile)
350+
.def("make_iterator_keep_alive", [](IntPairs& self) {
351+
return py::make_iterator(self, py::keep_alive<0, 1>());
352+
}, py::keep_alive<0, 1>())
353+
.def("simple_iterator", [](IntPairs& self) {
354+
return py::make_iterator(self);
355+
}, py::keep_alive<0, 1>())
356+
.def("simple_keys", [](IntPairs& self) {
357+
return py::make_key_iterator(self);
358+
}, py::keep_alive<0, 1>())
359+
.def("simple_values", [](IntPairs& self) {
360+
return py::make_value_iterator(self);
361+
}, py::keep_alive<0, 1>())
362+
349363
// test iterator with keep_alive (doesn't work so not used at runtime, but tests compile)
350364
.def("make_iterator_keep_alive", [](IntPairs& self) {
351365
return py::make_iterator(self, py::keep_alive<0, 1>());

tests/test_sequences_and_iterators.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ def test_generalized_iterators_simple():
5959
(0, 5),
6060
]
6161
assert list(m.IntPairs([(1, 2), (3, 4), (0, 5)]).simple_keys()) == [1, 3, 0]
62+
assert list(m.IntPairs([(1, 2), (3, 4), (0, 5)]).simple_values()) == [2, 4, 5]
6263

6364

6465
def test_iterator_referencing():

0 commit comments

Comments
 (0)