Boost logo

Boost Users :

Subject: Re: [Boost-users] Using single-pass ranges.
From: Jeffrey Lee Hellrung, Jr. (jeffrey.hellrung_at_[hidden])
Date: 2012-08-03 19:51:12


On Fri, Aug 3, 2012 at 3:15 AM, Robert Jones <robertgbjones_at_[hidden]>wrote:

> Hi All,
>
> When a range is constructed from a 'getNextThing()' sort of interface, it
> seems quite
> reasonable for that interface to return references to an abstract type.
> However that doesn't
> seem to be supported by Boost.IteratorFacade. I guess this only comes up
> in this context,
> as you couldn't construct a container of abstract objects, but is this a
> know limitation of
> iterator_facade?
>
> Full source attached.
>
> Thx, Rob.
>
> #include <iostream>
> #include <boost/iterator/iterator_facade.hpp>
> #include <boost/range/iterator_range.hpp>
> #include <boost/range/algorithm/for_each.hpp>
> #include <boost/range/adaptor/filtered.hpp>
>
> struct AbstractThing {
> virtual char get_c( ) const = 0;
> virtual ~AbstractThing( ) { }
> };
>
> struct Thing : AbstractThing {
> Thing( char c ) : c( c ) { }
> char get_c( ) const { return c; }
> private:
> char c;
> };
>
> struct ThingFeed
> {
> ThingFeed( const char * thing_values ) : m_current_value( thing_values
> ) { }
> AbstractThing * getNextThing( ) { return * m_current_value ? new
> Thing( * m_current_value ++ ) : 0; }
> private:
> const char * m_current_value;
> };
>
> struct ThingIterator : public boost::iterator_facade<ThingIterator,
> AbstractThing, boost::single_pass_traversal_tag>
> {
> ThingIterator( ThingFeed & feed, AbstractThing * cur = NULL ) : m_feed(
> feed ), m_cur( cur ) {}
>
> bool equal( const ThingIterator & other ) const { return m_cur ==
> other.m_cur; }
> void increment( ) { m_cur = m_feed.getNextThing( ); }
> AbstractThing & dereference( ) const { return * m_cur; }
>
> private:
>
> ThingFeed & m_feed;
> AbstractThing * m_cur;
> };
>
> struct ThingRange : public boost::iterator_range<ThingIterator>
> {
> ThingRange( ThingFeed & feed )
> : boost::iterator_range<ThingIterator>(
> ThingIterator( feed, feed.getNextThing( ) ),
> ThingIterator( feed ) )
> {}
> };
>
> void printThing( const AbstractThing & thing ) { std::cout << thing.get_c(
> ) << "\n"; }
>
> int main( )
> {
> ThingFeed feed( "abcd" );
> boost::for_each( ThingRange(feed), printThing );
> }
>
> > ~/local/gcc-4.6.2/bin/g++ -std=c++0x -I ~/local/boost_1_48_0/include -g
> -Werror -W -fno-strict-aliasing -fno-inline -Wall -Wno-uninitialized
> -Wcast-align -Wwrite-strings -Wunused -Wnon-virtual-dtor -Wextra -c -o
> iterate.o iterate.cpp
> In file included from iterate.cpp|2| 0:
> /home/rjones/local/boost_1_48_0/include/boost/iterator/iterator_facade.hpp:
> In instantiation of ‘boost::detail::postfix_increment_proxy<ThingIterator>’:
> /home/rjones/local/boost_1_48_0/include/boost/range/concepts.hpp|155 col
> 17| instantiated from
> ‘boost::range_detail::SinglePassIteratorConcept<Iterator>::~SinglePassIteratorConcept()
> [with Iterator = ThingIterator]’
> /home/rjones/local/boost_1_48_0/include/boost/concept/detail/general.hpp|38
> col 28| instantiated from ‘static void
> boost::concepts::requirement<boost::concepts::failed************
> Model::************>::failed() [with Model =
> boost::range_detail::SinglePassIteratorConcept<ThingIterator>]’
> /home/rjones/local/boost_1_48_0/include/boost/range/concepts.hpp|259 col
> 1| instantiated from ‘boost::SinglePassRangeConcept<const ThingRange>’
> /home/rjones/local/boost_1_48_0/include/boost/concept/detail/has_constraints.hpp|42
> col 5| instantiated from ‘const bool
> boost::concepts::not_satisfied<boost::SinglePassRangeConcept<const
> ThingRange> >::value’
> /home/rjones/local/boost_1_48_0/include/boost/concept/detail/has_constraints.hpp|45
> col 31| instantiated from
> ‘boost::concepts::not_satisfied<boost::SinglePassRangeConcept<const
> ThingRange> >’
> /home/rjones/local/boost_1_48_0/include/boost/mpl/if.hpp|67 col 11|
> instantiated from
> ‘boost::mpl::if_<boost::concepts::not_satisfied<boost::SinglePassRangeConcept<const
> ThingRange> >,
> boost::concepts::constraint<boost::SinglePassRangeConcept<const ThingRange>
> >, boost::concepts::requirement<boost::concepts::failed************
> boost::SinglePassRangeConcept<const ThingRange>::************> >’
> /home/rjones/local/boost_1_48_0/include/boost/concept/detail/general.hpp|50
> col 8| instantiated from ‘boost::concepts::requirement_<void
> (*)(boost::SinglePassRangeConcept<const ThingRange>)>’
> /home/rjones/local/boost_1_48_0/include/boost/range/algorithm/for_each.hpp|91
> col 1| instantiated from ‘UnaryFunction boost::range::for_each(const
> SinglePassRange&, UnaryFunction) [with SinglePassRange = ThingRange,
> UnaryFunction = void (*)(const AbstractThing&)]’
> iterate.cpp|55 col 51| instantiated from here
> /home/rjones/local/boost_1_48_0/include/boost/iterator/iterator_facade.hpp|158
> col 28| error: cannot declare field
> ‘boost::detail::postfix_increment_proxy<ThingIterator>::stored_value’ to be
> of abstract type ‘AbstractThing’
> iterate.cpp|7 col 8| note: because the following virtual functions are
> pure within ‘AbstractThing’:
> iterate.cpp|8 col 18| note: virtual char AbstractThing::get_c() const
>

This might work if, as the error suggests, you define your own
post-increment operator in the derived class, rather than using the one
provided by iterator_facade. Although, I'm not sure, it might not be
possible for *(i++) to work in this case without actually holding the
result of *i prior to the increment, which precludes the use of an abstract
reference type.

Let me know if that answers your inquiry.

- Jeff



Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net