Opened 7 years ago

#11287 new Bugs

adaptors: strided does not support input iterators

Reported by: Akim Demaille <akim.demaille@…> Owned by: Neil Groves
Milestone: To Be Determined Component: range
Version: Boost 1.58.0 Severity: Problem
Keywords: Cc:

Description

Hi,

Despite what the documentation says, the stride adaptor does not support input iterators. This is a pity, since for instance its applicability to iterators to coroutines: see #11274.

Oliver Kowalke tracked down the issue, and built a small scale example that shows the problem: see http://lists.boost.org/boost-users/2015/05/84277.php. The example is repeated below:

#include <iostream> 
#include <iterator> 
#include <vector> 
#include <boost/range.hpp> 
#include <boost/range/adaptor/strided.hpp> 
namespace foo { 
template< typename T > 
class X { 
private: 
    typedef std::vector< T > vec_t; 
    vec_t vec_; 
public: 
    X( vec_t const& vec) : 
        vec_( vec) { 
    } 
    class iterator : public std::iterator< std::input_iterator_tag, T > 
    { 
    private: 
        X * x_; 
        typename vec_t::iterator i_; 
    public: 
        typedef typename iterator::pointer pointer_t; 
        typedef typename iterator::reference reference_t; 
        iterator() : 
            x_( 0), i_() 
        {} 
        explicit iterator( X * x) : 
            x_( x), i_( x_->vec_.begin() ) 
        {} 
        iterator( iterator const& other) : 
            x_( other.x_), i_( other.i_) 
        {} 
        iterator & operator=( iterator const& other) { 
            if ( this == & other) return * this; 
            x_ = other.x_; 
            i_ = other.i_; 
            return * this; 
        } 
        bool operator==( iterator const& other) const 
        { return other.x_ == x_ && other.i_ == i_; } 
        bool operator!=( iterator const& other) const 
        { return other.x_ != x_ || other.i_ != i_; } 
        iterator & operator++() { 
            ++i_; 
            return * this; 
        } 
        iterator operator++( int) { 
            i_++; 
            return * this; 
        } 
        reference_t operator*() const 
        { return * i_; } 
        pointer_t operator->() const 
        { return & ( * i_); } 
    }; 
    class const_iterator : public std::iterator< std::input_iterator_tag, 
const T > 
    { 
    private: 
        X * x_; 
        typename vec_t::const_iterator i_; 
    public: 
        typedef typename iterator::pointer pointer_t; 
        typedef typename iterator::reference reference_t; 
        const_iterator() : 
            x_( 0), i_() 
        {} 
        explicit const_iterator( X * x) : 
            x_( x), i_( x_->vec_.begin() ) 
        {} 
        const_iterator( const_iterator const& other) : 
            x_( other.x_), i_( other.i_) 
        {} 
        const_iterator & operator=( const_iterator const& other) { 
            if ( this == & other) return * this; 
            x_ = other.x_; 
            i_ = other.i_; 
            return * this; 
        } 
        bool operator==( const_iterator const& other) const 
        { return other.x_ == x_ && other.i_ == i_; } 
        bool operator!=( const_iterator const& other) const 
        { return other.x_ != x_ || other.i_ != i_; } 
        const_iterator & operator++() { 
            ++i_; 
            return * this; 
        } 
        const_iterator operator++( int) { 
            i_++; 
            return * this; 
        } 
        reference_t operator*() const 
        { return * i_; } 
        pointer_t operator->() const 
        { return & ( * i_); } 
    }; 
    friend class iterator; 
    friend class const_iterator; 
}; 
template< typename T > 
typename X< T >::iterator 
range_begin( X< T > & c) 
{ return typename X< T >::iterator( & c); } 
template< typename T > 
typename X< T >::const_iterator 
range_begin( X< T > const& c) 
{ return typename X< T >::const_iterator( & c); } 
template< typename T > 
typename X< T >::iterator 
range_end( X< T > &) 
{ return typename X< T >::iterator(); } 
template< typename T > 
typename X< T >::const_iterator 
range_end( X< T > const&) 
{ return typename X< T >::const_iterator(); } 
template< typename T > 
typename X< T >::iterator 
begin( X< T > & c) 
{ return boost::begin( c); } 
template< typename T > 
typename X< T >::const_iterator 
begin( X< T > const& c) 
{ return boost::begin( c); } 
template< typename T > 
typename X< T >::iterator 
end( X< T > & c) 
{ return boost::end( c); } 
template< typename T > 
typename X< T >::const_iterator 
end( X< T > const& c) 
{ return boost::end( c); } 
} 
namespace boost { 
template< typename T > 
struct range_mutable_iterator< foo::X< T > > 
{ typedef typename foo::X< T >::iterator type; }; 
template< typename T > 
struct range_const_iterator< foo::X< T > > 
{ typedef typename foo::X< T >::const_iterator type; }; 
} 
int main() 
{ 
    std::vector< int > vec = { 1,2,3,4,5,6,7,8,9,10 }; 
    auto x = foo::X< int >( vec); 
    for (auto i : x | boost::adaptors::strided( 2) ) 
        std::cout << i << " "; 
    std::cout << '\n'; 
} 

Change History (0)

Note: See TracTickets for help on using tickets.