problem storing different iterators in a container

L

Lutz Altmann

Hi there :)

I'm trying to write a functor-class, which supports the de-
multiplexing of data from one
input-container to two or multiple output containers (de-
interleaving).

For example:

vec1 = [1 5 2 6 3 7]

#demultiplex vec1 -> result1,result2

result1 = [1 2 3]
result2 = [5 6 7]

The idea is, to provide a functor-class , which makes the de-
multiplexing very easy to use:
It should be possible to do soemthing like this:

DemuxFunctor func;
func.addChannel(output_iter);
func.addChannel(output_iter2);
...
...
for_each(input_vec.begin(),input_vec.end(),func);

It should be possible to "register" iterators to which the functor
writes the output-data.

here is my draft :

#include <vector>
#include <iterator>

using namespace std;

template<typename T>
class DemuxFunctor : public unary_function<void,T>
{

public:

DemuxFunctor():m_current(0){}

void operator()(const T& arg)
{
// add arg to one of the iterators
*(m_outchannels(m_current)) = arg;
// step ahead
(m_outchannels(m_current))++;

if (m_current >= m_outchannels.size())
{
m_current = 0;
}
else
{
m_current++;
}

}

template<typename X>
void addChannel(insert_iterator<X>& iter)
{
m_outchannels.push_back(iter);
}

private:

// PROBLEM : how to declare this vector !!!
vector<insert_iterator&> m_outchannels;..

unsigned int m_current;

};

The Problem is, that i have to save the (registered) iterators in a
data-structure - but because
different kinds of iterators (vectors,lists..) should be possible i
dont know how to declare the
iterator-vector .. is there a solution?!
Maybe you also have some princible comments to the design.

Regards,
Lutz
 
A

Alf P. Steinbach

* Lutz Altmann:
Hi there :)

I'm trying to write a functor-class, which supports the de-
multiplexing of data from one
input-container to two or multiple output containers (de-
interleaving).

For example:

vec1 = [1 5 2 6 3 7]

#demultiplex vec1 -> result1,result2

result1 = [1 2 3]
result2 = [5 6 7]

The idea is, to provide a functor-class , which makes the de-
multiplexing very easy to use:
It should be possible to do soemthing like this:

DemuxFunctor func;
func.addChannel(output_iter);
func.addChannel(output_iter2);
..
..
for_each(input_vec.begin(),input_vec.end(),func);

It should be possible to "register" iterators to which the functor
writes the output-data.

here is my draft :

#include <vector>
#include <iterator>

using namespace std;

template<typename T>
class DemuxFunctor : public unary_function<void,T>
{

public:

DemuxFunctor():m_current(0){}

void operator()(const T& arg)
{
// add arg to one of the iterators
*(m_outchannels(m_current)) = arg;
// step ahead
(m_outchannels(m_current))++;

if (m_current >= m_outchannels.size())
{
m_current = 0;
}
else
{
m_current++;
}

}

template<typename X>
void addChannel(insert_iterator<X>& iter)
{
m_outchannels.push_back(iter);
}

private:

// PROBLEM : how to declare this vector !!!
vector<insert_iterator&> m_outchannels;..

unsigned int m_current;

};

The Problem is, that i have to save the (registered) iterators in a
data-structure - but because
different kinds of iterators (vectors,lists..) should be possible i
dont know how to declare the
iterator-vector .. is there a solution?!
Maybe you also have some princible comments to the design.

The simplest seems to be to use run-time polymorphism.

std::vector< boost::shared_ptr< AbstractOutputIterator > > m_outchannels;

where AbstractOutputIterator has a templated derived class, template parameter
being the concrete iterator type in question.

This is so common a technique that I'm almost sure it must have a design pattern
name.


Cheers, & hth.,

- Alf
 
L

Lutz Altmann

* Lutz Altmann:


I'm trying to write a functor-class, which supports the de-
multiplexing of data from one
input-container to two or multiple output containers (de-
interleaving).
For example:
vec1 = [1 5 2 6 3 7]
#demultiplex vec1 -> result1,result2
result1 = [1 2 3]
result2 = [5 6 7]
The idea is, to provide a functor-class , which makes the de-
multiplexing very easy to use:
It should be possible to do soemthing like this:
DemuxFunctor func;
func.addChannel(output_iter);
func.addChannel(output_iter2);
..
..
for_each(input_vec.begin(),input_vec.end(),func);
It should be possible to "register" iterators to which the functor
writes the output-data.
here is my draft :
#include <vector>
#include <iterator>
using namespace std;
template<typename T>
class DemuxFunctor : public unary_function<void,T>
{


void operator()(const T& arg)
{
// add arg to one of the iterators
*(m_outchannels(m_current)) = arg;
// step ahead
(m_outchannels(m_current))++;
if (m_current >= m_outchannels.size())
{
m_current = 0;
}
else
{
m_current++;
}

template<typename X>
void addChannel(insert_iterator<X>& iter)
{
m_outchannels.push_back(iter);
}

// PROBLEM : how to declare this vector !!!
vector<insert_iterator&> m_outchannels;..
unsigned int m_current;

The Problem is, that i have to save the (registered) iterators in a
data-structure - but because
different kinds of iterators (vectors,lists..) should be possible i
dont know how to declare the
iterator-vector .. is there a solution?!
Maybe you also have some princible comments to the design.

The simplest seems to be to use run-time polymorphism.

std::vector< boost::shared_ptr< AbstractOutputIterator > > m_outchannels;

where AbstractOutputIterator has a templated derived class, template parameter
being the concrete iterator type in question.

This is so common a technique that I'm almost sure it must have a design pattern
name.

Cheers, & hth.,

- Alf

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?

can you please specify this a little bit more detailled ?
 
J

Junchen WANG

Hi there :)

I'm trying to write a functor-class, which supports the de-
multiplexing of data from one
input-container to two or multiple output containers (de-
interleaving).

For example:

vec1 = [1 5 2 6 3 7]

#demultiplex vec1 -> result1,result2

result1 = [1 2 3]
result2 = [5 6 7]

The idea is, to provide a functor-class , which makes the de-
multiplexing very easy to use:
It should be possible to do soemthing like this:

DemuxFunctor func;
func.addChannel(output_iter);
func.addChannel(output_iter2);
..
..
for_each(input_vec.begin(),input_vec.end(),func);

It should be possible to "register" iterators to which the functor
writes the output-data.

here is my draft :

#include <vector>
#include <iterator>

using namespace std;

template<typename T>
class DemuxFunctor : public unary_function<void,T>
{

public:

DemuxFunctor():m_current(0){}

void operator()(const T& arg)
{
// add arg to one of the iterators
*(m_outchannels(m_current)) = arg;
// step ahead
(m_outchannels(m_current))++;

if (m_current >= m_outchannels.size())
{
m_current = 0;
}
else
{
m_current++;
}

}

template<typename X>
void addChannel(insert_iterator<X>& iter)
{
m_outchannels.push_back(iter);
}

private:

// PROBLEM : how to declare this vector !!!
vector<insert_iterator&> m_outchannels;..

unsigned int m_current;

};

The Problem is, that i have to save the (registered) iterators in a
data-structure - but because
different kinds of iterators (vectors,lists..) should be possible i
dont know how to declare the
iterator-vector .. is there a solution?!
Maybe you also have some princible comments to the design.

Regards,
Lutz

#include <vector>
#include <iterator>
#include <functional>
#include <iostream>
using namespace std;


template<typename T>
class DemuxFunctor : public unary_function<void,T>
{
public:
DemuxFunctor():m_current(0){}
private:
class AbstractWrapper
{
public:
virtual void operator = (const T & arg) = 0;
virtual void operator ++ (int) = 0;
};
public:
template<typename IterType>
class WrapperIterator : public AbstractWrapper
{
public:
WrapperIterator(IterType & it) : _iter(it)
{

}
void operator = (const T & arg)
{
*_iter = arg;
}
void operator ++ (int)
{
_iter ++;
}
private:
IterType & _iter;
};
void operator()(const T& arg)
{
// add arg to one of the iterators
*m_outchannels[m_current] = arg;
// step ahead
(*m_outchannels[m_current ++]) ++;
if (m_current >= m_outchannels.size())
{
m_current = 0;
}
}
void addChannel(AbstractWrapper *iter)
{
m_outchannels.push_back(iter);
}
private:
// PROBLEM : how to declare this vector !!!
vector<AbstractWrapper *> m_outchannels;
unsigned int m_current;
};

int main()
{
int buffer[] = {1, 2};
vector<int> a;
vector<int> b;
insert_iterator<vector<int> > ita(a, a.begin());
insert_iterator<vector<int> > itb(b, b.begin()) ;
DemuxFunctor<int>::WrapperIterator< insert_iterator<vector<int> > >
wa(ita);
DemuxFunctor<int>::WrapperIterator< insert_iterator<vector<int> > >
wb(itb);
DemuxFunctor<int> df;
df.addChannel(&wa);
df.addChannel(&wb);
for (int i = 0; i < 5; ++i)
{
df(i);
}
copy(a.begin(), a.end(), ostream_iterator<int>(cout, " "));
cout << endl;
copy(b.begin(), b.end(), ostream_iterator<int>(cout, " "));
cout << endl;
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Hope you may enjoy it~

Best Regards,
Junchen
 
K

Kai-Uwe Bux

Lutz said:
Hi there :)

I'm trying to write a functor-class, which supports the de-
multiplexing of data from one
input-container to two or multiple output containers (de-
interleaving).

For example:

vec1 = [1 5 2 6 3 7]

#demultiplex vec1 -> result1,result2

result1 = [1 2 3]
result2 = [5 6 7]

The idea is, to provide a functor-class , which makes the de-
multiplexing very easy to use:
It should be possible to do soemthing like this:

DemuxFunctor func;
func.addChannel(output_iter);
func.addChannel(output_iter2);
..
..
for_each(input_vec.begin(),input_vec.end(),func);

It should be possible to "register" iterators to which the functor
writes the output-data.

here is my draft :

#include <vector>
#include <iterator>

using namespace std;

template<typename T>
class DemuxFunctor : public unary_function<void,T>
{

public:

DemuxFunctor():m_current(0){}

void operator()(const T& arg)
{
// add arg to one of the iterators
*(m_outchannels(m_current)) = arg;
// step ahead
(m_outchannels(m_current))++;

if (m_current >= m_outchannels.size())
{
m_current = 0;
}
else
{
m_current++;
}

}

template<typename X>
void addChannel(insert_iterator<X>& iter)
{
m_outchannels.push_back(iter);
}

private:

// PROBLEM : how to declare this vector !!!
vector<insert_iterator&> m_outchannels;..

unsigned int m_current;

};

The Problem is, that i have to save the (registered) iterators in a
data-structure - but because
different kinds of iterators (vectors,lists..) should be possible i
dont know how to declare the
iterator-vector .. is there a solution?!
Maybe you also have some princible comments to the design.

How about duck-typing. The following AbstractOutputIterator<> template might
be a type that use can use.

#include <algorithm>

using std::swap;

template < typename ValueType >
class AbstractOutputIterator {

struct base {

virtual
~base ( void ) {}

virtual
base * clone ( void ) = 0;

virtual
base & operator= ( ValueType const & rhs ) = 0;

virtual
void inc ( void ) = 0;

};

template < typename Iterator >
struct derived : public base {

Iterator the_iter;

derived ( Iterator iter )
: the_iter ( iter )
{}

~derived ( void ) {}

derived * clone ( void ) {
return ( new derived ( the_iter ) );
}

derived & operator= ( ValueType const & rhs ) {
the_iter = rhs;
return ( *this );
}

void inc ( void ) {
++ the_iter;
}

};

base * data_ptr;

public:

AbstractOutputIterator ( void )
: data_ptr ( 0 )
{}

template < typename Iterator >
AbstractOutputIterator ( Iterator iter )
: data_ptr ( new derived< Iterator > ( iter ) )
{}

AbstractOutputIterator ( AbstractOutputIterator const & other )
: data_ptr ( other.data_ptr ? other.data_ptr->clone() : 0 )
{}

AbstractOutputIterator & operator= ( AbstractOutputIterator rhs ) {
swap( *this, rhs );
return ( *this );
}

~AbstractOutputIterator ( void ) {
delete ( data_ptr );
}

friend
void swap ( AbstractOutputIterator & lhs, AbstractOutputIterator& rhs )
{
swap( lhs.data_ptr, rhs.data_ptr );
}

base & operator* ( void ) {
return ( *data_ptr );
}

AbstractOutputIterator & operator++ ( void ) {
data_ptr->inc();
return ( *this );
}

AbstractOutputIterator operator++ ( int ) {
AbstractOutputIterator result ( *this );
data_ptr->inc();
return ( result );
}

}; // AbstractOutputIterator


#include <vector>
#include <deque>
#include <list>
#include <iterator>
#include <algorithm>

int main ( void ) {
std::vector< int > iv;
std::deque< int > id;
std::list< int > il;

std::vector< AbstractOutputIterator<int> > iter;

iter.push_back( AbstractOutputIterator<int>
( std::back_inserter( iv ) ) );
iter.push_back( AbstractOutputIterator<int>
( std::back_inserter( id ) ) );
iter.push_back( AbstractOutputIterator<int>
( std::back_inserter( il ) ) );

* (iter[0]) ++ = 1;
* (iter[1]) ++ = 1;
* (iter[2]) ++ = 1;
* (iter[0]) ++ = 2;
* (iter[1]) ++ = 2;
* (iter[0]) ++ = 3;

std::copy( iv.begin(), iv.end(),
std::eek:stream_iterator<int>( std::cout, " " ) );
std::cout << '\n';
std::copy( id.begin(), id.end(),
std::eek:stream_iterator<int>( std::cout, " " ) );
std::cout << '\n';
std::copy( il.begin(), il.end(),
std::eek:stream_iterator<int>( std::cout, " " ) );
std::cout << '\n';
}


Note: the code is just a rough idea and has not been properly tested.


Best

Kai-Uwe Bux
 
L

Lutz Altmann

Lutz said:
I'm trying to write a functor-class, which supports the de-
multiplexing of data from one
input-container to two or multiple output containers (de-
interleaving).
For example:
vec1 = [1 5 2 6 3 7]
#demultiplex vec1 -> result1,result2
result1 = [1 2 3]
result2 = [5 6 7]
The idea is, to provide a functor-class , which makes the de-
multiplexing very easy to use:
It should be possible to do soemthing like this:
DemuxFunctor func;
func.addChannel(output_iter);
func.addChannel(output_iter2);
..
..
for_each(input_vec.begin(),input_vec.end(),func);
It should be possible to "register" iterators to which the functor
writes the output-data.
here is my draft :
#include <vector>
#include <iterator>
using namespace std;
template<typename T>
class DemuxFunctor : public unary_function<void,T>
{


void operator()(const T& arg)
{
// add arg to one of the iterators
*(m_outchannels(m_current)) = arg;
// step ahead
(m_outchannels(m_current))++;
if (m_current >= m_outchannels.size())
{
m_current = 0;
}
else
{
m_current++;
}

template<typename X>
void addChannel(insert_iterator<X>& iter)
{
m_outchannels.push_back(iter);
}

// PROBLEM : how to declare this vector !!!
vector<insert_iterator&> m_outchannels;..
unsigned int m_current;

The Problem is, that i have to save the (registered) iterators in a
data-structure - but because
different kinds of iterators (vectors,lists..) should be possible i
dont know how to declare the
iterator-vector .. is there a solution?!
Maybe you also have some princible comments to the design.

How about duck-typing. The following AbstractOutputIterator<> template might
be a type that use can use.

#include <algorithm>

using std::swap;

template < typename ValueType >
class AbstractOutputIterator {

struct base {

virtual
~base ( void ) {}

virtual
base * clone ( void ) = 0;

virtual
base & operator= ( ValueType const & rhs ) = 0;

virtual
void inc ( void ) = 0;

};

template < typename Iterator >
struct derived : public base {

Iterator the_iter;

derived ( Iterator iter )
: the_iter ( iter )
{}

~derived ( void ) {}

derived * clone ( void ) {
return ( new derived ( the_iter ) );
}

derived & operator= ( ValueType const & rhs ) {
the_iter = rhs;
return ( *this );
}

void inc ( void ) {
++ the_iter;
}

};

base * data_ptr;

public:

AbstractOutputIterator ( void )
: data_ptr ( 0 )
{}

template < typename Iterator >
AbstractOutputIterator ( Iterator iter )
: data_ptr ( new derived< Iterator > ( iter ) )
{}

AbstractOutputIterator ( AbstractOutputIterator const & other )
: data_ptr ( other.data_ptr ? other.data_ptr->clone() : 0 )
{}

AbstractOutputIterator & operator= ( AbstractOutputIterator rhs ) {
swap( *this, rhs );
return ( *this );
}

~AbstractOutputIterator ( void ) {
delete ( data_ptr );
}

friend
void swap ( AbstractOutputIterator & lhs, AbstractOutputIterator& rhs )
{
swap( lhs.data_ptr, rhs.data_ptr );
}

base & operator* ( void ) {
return ( *data_ptr );
}

AbstractOutputIterator & operator++ ( void ) {
data_ptr->inc();
return ( *this );
}

AbstractOutputIterator operator++ ( int ) {
AbstractOutputIterator result ( *this );
data_ptr->inc();
return ( result );
}

}; // AbstractOutputIterator

#include <vector>
#include <deque>
#include <list>
#include <iterator>
#include <algorithm>

int main ( void ) {
std::vector< int > iv;
std::deque< int > id;
std::list< int > il;

std::vector< AbstractOutputIterator<int> > iter;

iter.push_back( AbstractOutputIterator<int>
( std::back_inserter( iv ) ) );
iter.push_back( AbstractOutputIterator<int>
( std::back_inserter( id ) ) );
iter.push_back( AbstractOutputIterator<int>
( std::back_inserter( il ) ) );

* (iter[0]) ++ = 1;
* (iter[1]) ++ = 1;
* (iter[2]) ++ = 1;
* (iter[0]) ++ = 2;
* (iter[1]) ++ = 2;
* (iter[0]) ++ = 3;

std::copy( iv.begin(), iv.end(),
std::eek:stream_iterator<int>( std::cout, " " ) );
std::cout << '\n';
std::copy( id.begin(), id.end(),
std::eek:stream_iterator<int>( std::cout, " " ) );
std::cout << '\n';
std::copy( il.begin(), il.end(),
std::eek:stream_iterator<int>( std::cout, " " ) );
std::cout << '\n';

}

Note: the code is just a rough idea and has not been properly tested.

Best

Kai-Uwe Bux

hey thanks alot - i think i'll try to use this "duck-typing"
approach ..
from where do you know such things - maybe you have some hints where
to
get more insights in templates/iterators ..

regards,
Lutz Altmann
 
K

Kai-Uwe Bux

Lutz said:
On 16 Mrz., 19:56, Kai-Uwe Bux <[email protected]> wrote:
[something about a duck-type for output iterators]
hey thanks alot - i think i'll try to use this "duck-typing"
approach ..

Note that there are some limitations. For instance, virtual methods cannot
be templated. Therefore, you cannot make a true duck-type for output
iterators: you need to know in advance all types T for which

* iter ++ = t

will be meaningful. That's a little bit of a let-down due to a limitation of
the language. I have yet to find a way around that (and I doubt that such a
way exists).

from where do you know such things

I lifted this one from tr1::function.

- maybe you have some hints where
to get more insights in templates/iterators ..

Well, there are

a) "Modern C++ Design" by Alexandrescu.
b) "C++ Templates: the complete guide" by Vandervoorde and Jusuttis.
c) the Boost libraries.


Best

Kai-Uwe Bux
 
L

Lutz Altmann

Thanks,

i like this solution very much ..
the push_back in your example main() method can be further
simplified :
from:
iter.push_back( AbstractOutputIterator<int>
( std::back_inserter( il ) ) );
to:
iter.push_back(std::back_inserter(...)));

because of implicit-conversion. thats wonderful :)
exactly what i wanted..

what does it mean, that virtual methods cannot be templated.
Do you mean function-templates ? or are virtual functions (in
princible) of the not supported
by this pattern ?
I dont really understand, what you mean with : all types for T have to
be known in advance ..
for me, that seems not to be the case ?
i would be very thankfuk, if you could clarify this.

thanks ;)
Lutz Altmann

Lutz said:
On 16 Mrz., 19:56, Kai-Uwe Bux <[email protected]> wrote:

[something about a duck-type for output iterators]
hey thanks alot - i think i'll try to use this "duck-typing"
approach ..

Note that there are some limitations. For instance, virtual methods cannot
be templated. Therefore, you cannot make a true duck-type for output
iterators: you need to know in advance all types T for which

* iter ++ = t

will be meaningful.
the language. I have yet to find a way around that (and I doubt that such a
way exists).
from where do you know such things

I lifted this one from tr1::function.
- maybe you have some hints where
to get more insights in templates/iterators ..

Well, there are

a) "Modern C++ Design" by Alexandrescu.
b) "C++ Templates: the complete guide" by Vandervoorde and Jusuttis.
c) the Boost libraries.

Best

Kai-Uwe Bux
 
K

Kai-Uwe Bux

Lutz said:
Thanks,

i like this solution very much ..
the push_back in your example main() method can be further
simplified :
from:
iter.push_back( AbstractOutputIterator<int>
( std::back_inserter( il ) ) );
to:
iter.push_back(std::back_inserter(...)));

because of implicit-conversion. thats wonderful :)
exactly what i wanted..

what does it mean, that virtual methods cannot be templated.
Do you mean function-templates ? or are virtual functions (in
princible) of the not supported
by this pattern ?

I mean that you cannot do:

class X {

...

template < typname Arg >
virtual
void member_fct ( Arg arg ) { ... }

};

That really sucks.

I dont really understand, what you mean with : all types for T have to
be known in advance ..
for me, that seems not to be the case ?
i would be very thankfuk, if you could clarify this.

Suppose for a second, you could have templated virtual member functions.
Then, you could do:

class AbstractOutputIterator {

struct base {

virtual
~base ( void ) {}

virtual
base * clone ( void ) = 0;

template < typename ValueType >
virtual
base & operator= ( ValueType const & rhs ) = 0;

virtual
void inc ( void ) = 0;

};

template < typename Iterator >
struct derived : public base {

Iterator the_iter;

derived ( Iterator iter )
: the_iter ( iter )
{}

~derived ( void ) {}

derived * clone ( void ) {
return ( new derived ( the_iter ) );
}

template < typename ValueType >
derived & operator= ( ValueType const & rhs ) {
the_iter = rhs;
return ( *this );
}

void inc ( void ) {
++ the_iter;
}

};

...

};

Now, AbstractOutputIterator would be much closer to actual output iterators
in that it isn't tied to a particular ValueType in the assignment

* abstract_iter ++ = some_expression;


Since the language does not support this, you would have to need all
permitted types for some_expression in advance. In the code I posted, I
turned that into the template parameter for AbstractOutputIterator.


Oh, and please don't top-post.
Lutz said:
On 16 Mrz., 19:56, Kai-Uwe Bux <[email protected]> wrote:

[something about a duck-type for output iterators]
hey thanks alot - i think i'll try to use this "duck-typing"
approach ..

Note that there are some limitations. For instance, virtual methods
cannot be templated. Therefore, you cannot make a true duck-type for
output iterators: you need to know in advance all types T for which

* iter ++ = t

will be meaningful.
the language. I have yet to find a way around that (and I doubt that such
a way exists).
[snip]


Best

Kai-Uwe Bux
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,480
Members
44,900
Latest member
Nell636132

Latest Threads

Top