Skip to content

Commit 93c0a38

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

File tree

3 files changed

+24
-8
lines changed

3 files changed

+24
-8
lines changed

include/pybind11/pybind11.h

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1966,27 +1966,28 @@ 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 &>()));
19741975
result_type operator()(Iterator &it) const {
19751976
return *it;
19761977
}
19771978
};
19781979

1979-
template <typename Iterator>
1980+
template <typename Iterator, typename ResultType = decltype(((*std::declval<Iterator &>()).first)) >
19801981
struct iterator_key_access {
1981-
using result_type = decltype(((*std::declval<Iterator>()).first));
1982+
using result_type = decltype(((*std::declval<Iterator &>()).first));
19821983
result_type operator()(Iterator &it) const {
19831984
return (*it).first;
19841985
}
19851986
};
19861987

1987-
template <typename Iterator>
1988+
template <typename Iterator, typename ResultType = decltype(((*std::declval<Iterator &>()).second))>
19881989
struct iterator_value_access {
1989-
using result_type = decltype(((*std::declval<Iterator>()).second));
1990+
using result_type = decltype(((*std::declval<Iterator &>()).second));
19901991
result_type operator()(Iterator &it) const {
19911992
return (*it).second;
19921993
}

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)