Opened 5 years ago
Closed 5 years ago
#13094 closed Bugs (invalid)
boost::adaptors::transform fails to preserve bidirectional behavior of range
| Reported by: | Owned by: | Neil Groves | |
|---|---|---|---|
| Milestone: | To Be Determined | Component: | range | 
| Version: | Boost 1.64.0 | Severity: | Problem | 
| Keywords: | range adaptors transform | Cc: | 
Description
The documentation of boost::adaptors::transform states the returned range type is the same as the argument range type.  However, when wrapping std::vector, the iterators returned are not bidirectional as the std::vector iterators are.  std::advance with a negative integer leaves them unchanged and std::prev fails to compile with them.  They do work as expected with operator-.
#include <iostream> #include <vector> #include <iterator> #include <boost/range/adaptor/transformed.hpp> int main() { std::vector<int> data{1,2,3}; auto transformed = boost::adaptors::transform(data, [](int x) { return x; }); auto iter = transformed.begin(); // auto iter = data.begin(); // swap to compare std::cout << "begin: " << *iter << std::endl; // prints 1 both cases std::advance(iter, 1); std::cout << "begin+1: " << *iter << std::endl; // prints 2 both cases std::advance(iter, -1); // prints 2 for boost adaptor, 1 for std::vector std::cout << "begin+1-1: " << *iter << std::endl; std::cout << "begin+1-1 (v2): " << *(iter - 1) << std::endl; // prints 1 both cases // std::prev(iter); // boost fails bidirectional test, won't compile return 0; }
Change History (2)
comment:1 by , 5 years ago
comment:2 by , 5 years ago
| Resolution: | → invalid | 
|---|---|
| Status: | new → closed | 
Random Access Traversal Iterator (in the Boost iterator traversal concepts) is not the same thing as Random Access Iterator (in the Standard iterator categories).
The former just specifies traversal requirements,
but the latter also specifies value access requirements.
(For more details, please consult to the documentation of Boost.Iterator.)
For example, Random Access Iterator requires that iterator's reference type is
a real reference. The iterator in the test case fails to satisfy this requirement.
That being said, I think it would be useful to have boost::advance,
which is parameterized by the Boost iterator traversal concepts.
I'm going to ask about it on the developer ML.

By the way I see this with both clang and Visual Studio libraries. It seems that
std::advance,std::prev, etc are relying onstd::iterator_traits<Iter>::iterator_categorytag dispatch, which forstd::vectoryields:std::random_access_iterator_tagBut for
boost::adaptors::transformyields:boost::iterators::detail::iterator_category_with_traversal<std::input_iterator_tag, boost::iterators::random_access_traversal_tag>It looks like there may be code for boost to understand the standard library
iterator_categorytags in terms of traversals, but the opposite does not work; this causes behavior changes when passing to code using standard library conventions when the code is modified from passing standard types to boost adaptor types.