
Thorsten Ottosen wrote:
joaquin@tid.es skrev:
Beman Dawes escribió:
Attached is proof-of-concept code for a sentinel iterator adapter. It turns a pointer to sentinel terminated sequence, such as a C-style string, into a forward iterator with a conforming end iterator.
Having Sentinel specified as a non-type template parameter greatly reduces the category of types this can work with. I'd replace it with some SentinelFactory policy or something.
That is not a bad idea, although it would really be good if the basic case can stay as optimaized as currently (having a static member). I guess having a static member is not an option for a general policy, thus giving us the usual iterator problem of double storage.
I don't understand the rationale for m_sentinel. Couldn't the code refer to Sentinel directly as a compile time constant as opposed to a static member variable? It seems like Beman had two different things in mind. What he seems to want is for the 2nd template parameter of sentinel_iterator to be something that can cast to T or T itself and default to default constructed T. The code below seems to work... Regards, Luke #include <cassert> // sentinel terminated sequence iterator template < class T, typename Sentinel = T > class sentinel_iterator { public: sentinel_iterator() : m_ptr(0) {} // construct end iterator sentinel_iterator( T * p ) : m_ptr( (p && *p != Sentinel()) ? p : 0 ) {} sentinel_iterator & operator++() { assert(m_ptr); if ( *++m_ptr == Sentinel() ) m_ptr = 0; return *this; } T & operator*() const { assert(m_ptr); return *m_ptr; } bool operator==( const sentinel_iterator & rhs ) const { return m_ptr == rhs.m_ptr; } bool operator!=( const sentinel_iterator & rhs ) const { return m_ptr != rhs.m_ptr; } private: T * m_ptr; // 0 == the end iterator //static const T m_sentinel = Sentinel(); }; struct s_val { operator int () const { return -1; } }; int main() { // test cases using default sentinel sentinel_iterator<char> it( "abc" ); assert( it != sentinel_iterator<char>() ); assert( *it == 'a' ); assert( *++it == 'b' ); assert( *++it == 'c' ); assert( ++it == sentinel_iterator<char>() ); sentinel_iterator<char> it2( "" ); assert( it2 == sentinel_iterator<char>() ); sentinel_iterator<char> it3( 0 ); assert( it3 == sentinel_iterator<char>() ); // test cases using non-default sentinel typedef sentinel_iterator<unsigned, s_val> my_iter_type; unsigned data[] = { 0, 1, -1 }; my_iter_type my_it( data ); assert( my_it != my_iter_type() ); assert( *my_it == 0 ); assert( *++my_it == 1 ); assert( ++my_it == my_iter_type() ); unsigned my_sentinel = -1; my_iter_type my_it2( &my_sentinel ); assert( my_it2 == my_iter_type() ); my_iter_type my_it3( 0 ); assert( my_it3 == my_iter_type() ); return 0; }