On Fri, Aug 3, 2012 at 3:15 AM, Robert Jones <robertgbjones@gmail.com> 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