c++ - Polymorphic converting iterator -


consider following (simplified) scenario:

class edgeone {   private:     ...   public:     int startnode();     int endnode(); };  class containerone {   private:     std::vector<edgeone> _edges;   public:     std::vector<edgeone>::const_iterator edgesbegin(){       return _edges.begin();     };     std::vector<edgeone>::const_iterator edgesend(){       return _edges.end();     }; };  class edgetwo {   private:     ...   public:     int startnode();     int endnode(); };  class containertwo {   private:     std::vector<edgetwo> _edges;   public:     std::vector<edgetwo>::const_iterator edgesbegin(){       return _edges.begin();     };     std::vector<edgetwo>::const_iterator edgesend(){       return _edges.end();     }; }; 

i.e., have 2 identical edge types , 2 identical container types. can iterate on each kind individually. far, fine.

but use case following: based on criteria, either containerone or containertwo object. need iterate on edges. because types different, cannot easily without code duplication.

so idea following: want have iterator following properties: - regarding traversal behavior, behaves either std::vector<edgeone>::const_iterator or std::vector<edgetwo>::const_iterator, depending on how initialized. - instead of returning const edgeone & or const edgetwo &, operator* should return std::pair<int,int>, i.e., apply conversion.

i found boost.iterator library, in particular:

  • iterator_facade, helps build standard-conforming iterator and
  • transform_iterator, used transform edgeone , edgetwo std::pair<int,int>, not sure how complete solution should like. if build entire iterator myself, there benefit use transform_iterator, or make solution more heavy-weight?

i guess iterator needs store following data:

  • a flag (bool sufficient moment, enum value easier extend if necessary) indicating whether value type edgeone or edgetwo.
  • a union entries both iterator types (where 1 matches flag ever accessed).

anything else can computed on-the-fly.

i wonder if there existing solution polymorphic behavior, i.e. iterator implementation combining 2 (or more) underlying iterator implementation same value type. if such thing exists, use combine 2 transform_iterators.

dispatching (i.e., deciding whether containerone or containertwo object needs accessed) done freestanding function ...

any thoughts or suggestions regarding issue?

template<typename t1, typename t2> boost::variant<t1*, t2*> get_nth( boost::variant< std::vector<t1>::iterator, std::vector<t2>::iterator > begin, std::size_t n ) {   // either t1 or t2 whichever vector have pointer }  // implement using boost::iterator utilities, think fascade might right 1 // takes function takes index, , returns nth element.  compares // equality based on index, , moves position based on index: template<typename lambda> struct generator_iterator {   std::size_t index;   lambda f; }; template<typename lambda> generator_iterator< typename std::decay<lambda>::type > make_generator_iterator( lambda&&, std::size_t index=0 );  boost::variant< it1, it2 > begin; // set either 1 of begins auto double_begin = make_generator_iterator( [begin](std::size_t n){return get_nth( begin, n );} ); auto double_end = double_begin + number_of_elements; // number_of_elements how big container type-erasing 

now have iterator can iterate on one, or other, , returns boost::variant<t1*, t2*>.

we can write helper function uses visitor extract 2 fields want returned variant, , treat adt. if dislike adts, can instead write class wraps variant , provides methods, or change get_nth less generic , instead return struct data produced.

there going equivalent of branch on each access, there no virtual function overhead in plan. requires auto typed variable, can write explicit functor replace lambda [begin](std::size_t n){return get_nth( begin, n );} , issue goes away.

easier solutions:

write for_each function iterates on each of containers, , passes in processed data passed in function.

struct simple_data { int x,y; }; std::function<std::function<void(simple_data)>> for_each() const {   auto begin = _edges.begin();   auto end = _edges.end();   return [begin,end](std::function<void(simple_data)> f) {     for(auto = begin; != end; ++it) {       simple_data d;       d.x = it->getx();       d.y = it->gety();       f(d);     }   }; }; 

and similar in other. can iterate on contents without caring details calling foo->foreach()( [&](simple_data d) { /*code*/ } );, , because stuffed foreach std::function return value instead of doing directly, can pass concept of looping around function.

as mentioned in comments, other solutions can include using boost's type-erased iterator wrappers, or writing python-style generator mutable generator returns either simple_data. directly use boost iterator-creation functions create iterator on boost::variant<t1, t2>.


Comments

Popular posts from this blog

php - Calling a template part from a post -

Firefox SVG shape not printing when it has stroke -

How to mention the localhost in android -