id,summary,reporter,owner,description,type,status,milestone,component,version,severity,resolution,keywords,cc 9812,"BinaryOperation boost::transform only stops when it reaches the end of rng1, even if rng2 is shorter",David Sanders ,Neil Groves,"Here's a complete program that reproduces the problem: #include #include namespace std { ostream& operator<<(ostream& stream, const pair& p) { return stream << ""("" << p.first << "", "" << p.second << "")""; } } int main() { boost::transform( boost::irange(0, 100), boost::irange(0, 10), std::ostream_iterator>(std::cout, ""\n""), [](const int left, const int right) { return std::make_pair(left, right); }); return EXIT_SUCCESS; } I compile on Fedora 20 using g++ 4.8.2. Here's the output I get: g++ transform.cpp -std=c++11 && ./a.out (0, 0) (1, 1) (2, 2) (3, 3) (4, 4) (5, 5) (6, 6) (7, 7) (8, 8) (9, 9) a.out: /usr/include/boost/range/algorithm/transform.hpp:63: OutputIterator boost::range_detail::transform_impl(SinglePassTraversalReadableIterator1, SinglePassTraversalReadableIterator1, SinglePassTraversalReadableIterator2, SinglePassTraversalReadableIterator2, OutputIterator, BinaryFunction) [with SinglePassTraversalReadableIterator1 = boost::range_detail::integer_iterator; SinglePassTraversalReadableIterator2 = boost::range_detail::integer_iterator; OutputIterator = std::ostream_iterator >; BinaryFunction = main()::__lambda0]: Assertion `first2 != last2' failed. Abort Here's the code I believe to be broken in boost/range/algorithm/transform.hpp: template< class SinglePassTraversalReadableIterator1, class SinglePassTraversalReadableIterator2, class OutputIterator, class BinaryFunction > inline OutputIterator transform_impl(SinglePassTraversalReadableIterator1 first1, SinglePassTraversalReadableIterator1 last1, SinglePassTraversalReadableIterator2 first2, SinglePassTraversalReadableIterator2 last2, OutputIterator out, BinaryFunction fn) { for (; first1 != last1; ++first1, ++first2) { BOOST_ASSERT( first2 != last2 ); *out = fn(*first1, *first2); ++out; } return out; } Here's my proposed fix: template< class SinglePassTraversalReadableIterator1, class SinglePassTraversalReadableIterator2, class OutputIterator, class BinaryFunction > inline OutputIterator transform_impl(SinglePassTraversalReadableIterator1 first1, SinglePassTraversalReadableIterator1 last1, SinglePassTraversalReadableIterator2 first2, SinglePassTraversalReadableIterator2 last2, OutputIterator out, BinaryFunction fn) { for (; first1 != last1 && first2 != last2; ++first1, ++first2) { *out = fn(*first1, *first2); ++out; } return out; } I added a check that first2 != last2 and removed the ASSERT. Here's the relevant documentation: BinaryOperation version: transform assigns the value z to each element [out, out + min(distance(rng1), distance(rng2))), z = fun(x,y) where x is the corresponding value in rng1 and y is the corresponding value in rng2. This version of transform stops upon reaching either the end of rng1, or the end of rng2. Hence there isn't a requirement for distance(rng1) == distance(rng2) since there is a safe guaranteed behaviour, unlike with the iterator counterpart in the standard library. ------------------------------------------------- Please note that the original implementation doesn't meet the specification described above, whereas the new implementation does. BinaryOperation boost::for_each has a similar specification, but it implements it correctly. Boost Rocks! Keep up the stellar work! Don't hesitate to contact me if any of the above needs further explanation. Thanks, David",Bugs,closed,Boost 1.56.0,range,Boost 1.54.0,Problem,fixed,,