[iterator] iterator-category logic

I'd like to ask Boosters' opinions on this. boost::iterator_facade determines the iterator_category via the logic outlined in http://www.boost.org/doc/libs/1_49_0/libs/iterator/doc/iterator_facade.html#... In particular, if (a) CategoryOrTraversal is a Boost traversal tag; and (b) Reference is not a "real" C++ reference (i.e., a proxy reference); then iterator_category is at best convertible to std::input_iterator_tag. This ends up being surprising to users who use boost::iterator_adaptor (note that, by default, iterator_adaptor passes the Boost traversal tag of the adapted iterator down to iterator_facade) to adapt, say, a pointer, define their adapted iterator to return a proxy reference, and find out that their standard library functions don't recognize their adapted iterator as a random access iterator. The usual workaround tends to be to just override the iterator_facade logic yourself to use a more refined iterator_category and hope your standard library functions don't barf. For better or for worse, the present logic in iterator_facade is strictly (more or less) correct given the C++03 iterator requirements, but I just looked up the N3290 draft of C++11 and it appears that any requirements that *i return a real reference have been dropped, thus allowing for proxy references in all iterator categories. (a) Am I interpreting the C++11 iterator requirements correctly? (b) If so, should iterator_facade's iterator-category logic be reworked to account for the new requirements? (c) If so, how should it be determined when to use the C++03 requirements and when to use the C++11 requirements? Thanks, - Jeff

Jeff, On Wed, Apr 18, 2012 at 2:20 AM, Jeffrey Lee Hellrung, Jr. <jeffrey.hellrung@gmail.com> wrote:
(b) Reference is not a "real" C++ reference (i.e., a proxy reference); then iterator_category is at best convertible to std::input_iterator_tag. This ends up being surprising to users who use boost::iterator_adaptor (note that, by default, iterator_adaptor passes the Boost traversal tag of the adapted iterator down to iterator_facade) to adapt, say, a pointer, define their adapted iterator to return a proxy reference, and find out that their standard library functions don't recognize their adapted iterator as a random access iterator. The usual workaround tends to be to just override the iterator_facade logic yourself to use a more refined iterator_category and hope your standard library functions don't barf.
For what it's worth, a recent thread indicated that VC10 standard library was being non-conformant in requiring that [1].
For better or for worse, the present logic in iterator_facade is strictly (more or less) correct given the C++03 iterator requirements, but I just looked up the N3290 draft of C++11 and it appears that any requirements that *i return a real reference have been dropped, thus allowing for proxy references in all iterator categories. (a) Am I interpreting the C++11 iterator requirements correctly? The changes seemed subtle to me, and I'm not adept at reading standardese, but that was my reading too.
(b) If so, should iterator_facade's iterator-category logic be reworked to account for the new requirements? I would like to see that. . .
(c) If so, how should it be determined when to use the C++03 requirements and when to use the C++11 requirements? My initial thought was that it should be based on the standard library -- if it assumes iterator_traits<T>::reference == iterator_traits<T>::value_type&, then 03 requirements should be used.
However, considering that user code could also have correctly assumed the same in 03, perhaps a very long, macro-controlled deprecation period is the right thing to do. [1] http://lists.boost.org/Archives/boost/2012/01/189715.php Thanks, Nate

On 18.04.2012 10:20, Jeffrey Lee Hellrung, Jr. wrote:
For better or for worse, the present logic in iterator_facade is strictly (more or less) correct given the C++03 iterator requirements, but I just looked up the N3290 draft of C++11 and it appears that any requirements that *i return a real reference have been dropped, thus allowing for proxy references in all iterator categories. (a) Am I interpreting the C++11 iterator requirements correctly?
I'm afraid not. I can only quote N3376 (the first draft of C++1y) right now, but it says in the requirements for forward iterators (24.2.5p1): "if X is a mutable iterator, /reference/ is a reference to T; if X is a const iterator, /reference/ is a reference to const T," where /reference/ refers to iterator_traits<X>::reference. And of course the primary Iterator requirements specify that *r returns iterator_traits<X>::reference. The change in iterator requirements was supposed to piggy-back on concepts; when they were removed, so were the iterator changes. They basically haven't changed since C++03. Sebastian

On Thu, Apr 19, 2012 at 5:09 AM, Sebastian Redl < sebastian.redl@getdesigned.at> wrote:
On 18.04.2012 10:20, Jeffrey Lee Hellrung, Jr. wrote:
For better or for worse, the present logic in iterator_facade is strictly (more or less) correct given the C++03 iterator requirements, but I just looked up the N3290 draft of C++11 and it appears that any requirements that *i return a real reference have been dropped, thus allowing for proxy references in all iterator categories. (a) Am I interpreting the C++11 iterator requirements correctly?
I'm afraid not. I can only quote N3376 (the first draft of C++1y) right now, but it says in the requirements for forward iterators (24.2.5p1): "if X is a mutable iterator, /reference/ is a reference to T; if X is a const iterator, /reference/ is a reference to const T," where /reference/ refers to iterator_traits<X>::reference. And of course the primary Iterator requirements specify that *r returns iterator_traits<X>::reference.
The change in iterator requirements was supposed to piggy-back on concepts; when they were removed, so were the iterator changes. They basically haven't changed since C++03.
:: sad face :: Thanks for checking this more thoroughly than I did :/ Sorry for the noise, - Jeff
participants (3)
-
Jeffrey Lee Hellrung, Jr.
-
Nathan Crookston
-
Sebastian Redl