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_category
tag dispatch, which forstd::vector
yields:std::random_access_iterator_tag
But for
boost::adaptors::transform
yields: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_category
tags 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.