[range]slicing any_range

Hello, I'm using the Boost.Range library (Version:1.55.0). When I use any_range with sliced adaptor, slicing operation doesn't return. Is my code something wrong? If it is a bug, I will create a ticket. Here is the minimized code that reproduces the situation: #include <vector> #include <iostream> #include <cassert> #include <boost/range/any_range.hpp> #include <boost/range/adaptor/sliced.hpp> typedef boost::any_range<int, boost::random_access_traversal_tag, int, std::ptrdiff_t> int_range; int main() { std::vector<int> v; v.push_back(0); v.push_back(1); v.push_back(2); { // works fine std::cout << "slice vector" << std::endl; int_range ir1 = v | boost::adaptors::sliced(0,2); std::cout << "slice vector finished" << std::endl; assert(ir1[0] == 0); assert(ir1[1] == 1); assert(ir1.size() == 2); } { int_range ir2(v); std::cout << "slice any_range" << std::endl; int_range ir3 = ir2 | boost::adaptors::sliced(0,2); // never return... std::cout << "slice any_range finished" << std::endl; assert(ir3[0] == 0); assert(ir3[1] == 1); assert(ir3.size() == 2); } } Takatoshi Kondo

I analyzed my program on the following environment: g++ 4.8.2 Linux archboltz 3.12.4-1-ARCH #1 SMP PREEMPT Sun Dec 8 21:18:00 CET 2013 x86_64 GNU/Linux In the file iterator_range_core.hpp , std::advance() is called. The type of BOOST_DEDUCED_TYPENAME range_iterator<Range>::type is boost::iterator_facade< boost::range_detail::any_iterator< int, boost::random_access_traversal_tag, int, long, boost::any_iterator_buffer<64ul>
template< class Range > inline iterator_range< BOOST_DEDUCED_TYPENAME range_iterator<Range>::type > make_range_impl( Range& r, BOOST_DEDUCED_TYPENAME range_difference<Range>::type advance_begin, BOOST_DEDUCED_TYPENAME range_difference<Range>::type advance_end ) { // // Not worth the effort // //if( advance_begin == 0 && advance_end == 0 ) // return make_iterator_range( r ); // BOOST_DEDUCED_TYPENAME range_iterator<Range>::type new_begin = boost::begin( r ), new_end = boost::end( r ); std::advance( new_begin, advance_begin ); std::advance( new_end, advance_end ); return make_iterator_range( new_begin, new_end ); } When std::advance() is called, it dispatched to the InputIterator overloading version of __advance(). My expectation was that dispatched to the RandomAccessIterator overloading version of __advance(). stl_iterator_base_funcs.h:121 template<typename _InputIterator, typename _Distance> inline void __advance(_InputIterator& __i, _Distance __n, input_iterator_tag) { // concept requirements __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>) _GLIBCXX_DEBUG_ASSERT(__n >= 0); while (__n--) ++__i; } Is that the problem relate to https://svn.boost.org/trac/boost/ticket/1296 ? To check the behavior of boost::random_access_traversal_tag and std::advance, I wrote the following code: #include <boost/iterator/iterator_facade.hpp> #include <vector> #include <iostream> struct my_iter:boost::iterator_facade<my_iter, int, boost::random_access_traversal_tag> { void advance(std::size_t v) { std::cout << "advance() is called with arg " << v << std::endl; } }; int main() { my_iter mit; std::advance(mit, 1); } Output: advance() is called with arg 1 When std::advance() is called, it dispatched to the RandomAccessIterator overloading version of __advance(). stl_iterator_base_funcs.h:148 template<typename _RandomAccessIterator, typename _Distance> inline void __advance(_RandomAccessIterator& __i, _Distance __n, random_access_iterator_tag) { // concept requirements __glibcxx_function_requires(_RandomAccessIteratorConcept< _RandomAccessIterator>) __i += __n; } And then, operator += called my_iter::advance(). I got stuck. Why any_range with boost::random_access_traversal_tag and my_iter with boost::random_access_traversal_tag behave differently. They both iterator_facade. Takatoshi Kondo On Tue, Dec 24, 2013 at 6:55 AM, Takatoshi Kondo <redboltz@gmail.com> wrote:

On Tue, Dec 24, 2013 at 8:48 PM, Takatoshi Kondo <redboltz@gmail.com> wrote:
typedef boost::any_range<int, boost::random_access_traversal_tag, int, std::ptrdiff_t> int_range;
I realized the problem in my code. int_range doesn't support a reference. It should be typedef boost::any_range<int, boost::random_access_traversal_tag, int&, std::ptrdiff_t> int_range; If the boost::iterator_facade is passed the template arguments boost::random_access_traversal_tag as Traversal and no reference type as Reference, the iterator_category is input_iterator due to a lack of reference support. I checked facade_iterator_category.hpp and wrote the following test code to clarify my understanding. #include <boost/iterator/iterator_facade.hpp> struct my_iter:boost::iterator_facade<my_iter, int, boost::random_access_traversal_tag, int&> {}; struct my_iter_noref:boost::iterator_facade<my_iter, int, boost::random_access_traversal_tag, int> {}; int main() { // has reference static_assert( std::is_convertible< std::iterator_traits<my_iter>::iterator_category, std::random_access_iterator_tag >::value, ""); // no reference static_assert( !std::is_convertible< std::iterator_traits<my_iter_noref>::iterator_category, std::random_access_iterator_tag >::value, ""); static_assert( std::is_convertible< std::iterator_traits<my_iter_noref>::iterator_category, std::input_iterator_tag >::value, ""); } Takatoshi Kondo
participants (1)
-
Takatoshi Kondo