iterator_traits::value_type on back_insert_iterator - returns void

A

anto.anish

Hello,

My Requirement is
1. Copy data from iterator to an array ( array should be created
dynamically within the function based on data_type of the data
held by the iterator /container. )

2. Copy data from array into iterator ( array should be created
dynamically within the function based on data_type of the data
held by the iterator /container. )

Implementation
-----------------------
//copies data from begin to end of container to array.
template <class T>
void writeiter( T& iter1, T& iter2)
{
int t2= iter2 -iter1;
cout <<t2<<endl;
iterator_traits<T>::value_type *twrite= new
iterator_traits<T>::value_type[t2];
std::copy(iter1,iter2,twrite);
}

//copies data from array to iter (back_insert_iterator)
template <class T> void readiter( T& iter, int len)
{
//This line does not compile since return is a void.
iterator_traits<T>::value_type *tread= new
iterator_traits<T>::value_type[len]; for (int i=0; i<len;++i)
tread = i;
std::copy(tread, tread+ len,iter );
}

int main()
{
vector <int> v1;
int len=5;
back_insert_iterator< vector<int> > v1back(v1);
readiter(v1back,len); //Does not work - the function does not compile

vector<int>::iterator vbdir1=v1.begin();
vector<int>::iterator vbdir2=v1.end();
writeiter(vbdir1,vbdir2); //works good

}

The readiter function does not compile since a
iterator_trait::value_type of back_insert_iterator's returns void.
what i would need is to get the datatype of the container which is INT
held by the back_insert_iterator. My assumption was that i would get
the iterator_traits of back_insert_iterator from function readiter ,
which would later be used to create an array or a array of pointers.

Any help appreciated?

Thanks
Anish
 
V

Victor Bazarov

My Requirement is
1. Copy data from iterator to an array ( array should be created
dynamically within the function based on data_type of the data
held by the iterator /container. )

2. Copy data from array into iterator ( array should be created
dynamically within the function based on data_type of the data
held by the iterator /container. )

Implementation
-----------------------
//copies data from begin to end of container to array.
template <class T>
void writeiter( T& iter1, T& iter2)
{
int t2= iter2 -iter1;
cout <<t2<<endl;
iterator_traits<T>::value_type *twrite= new
iterator_traits<T>::value_type[t2];
std::copy(iter1,iter2,twrite);
}

//copies data from array to iter (back_insert_iterator)
template <class T> void readiter( T& iter, int len)
{
//This line does not compile since return is a void.
iterator_traits<T>::value_type *tread= new
iterator_traits<T>::value_type[len]; for (int i=0; i<len;++i)
tread = i;
std::copy(tread, tread+ len,iter );
}

int main()
{
vector <int> v1;
int len=5;
back_insert_iterator< vector<int> > v1back(v1);
readiter(v1back,len); //Does not work - the function does not compile

vector<int>::iterator vbdir1=v1.begin();
vector<int>::iterator vbdir2=v1.end();
writeiter(vbdir1,vbdir2); //works good

}

The readiter function does not compile since a
iterator_trait::value_type of back_insert_iterator's returns void.


It doesn't "return" void. It's defined as 'void'. IOW, the insert
iterator (back_insert_iterator is an insert iterator) does NOT have
a value type because it cannot be _dereferenced_ except for the
purpose of _assigning_ to the result of dereferencing. The insert
iterators adhere to the rules defined for _output_ iterators. You
cannot expect to _input_ anything (like you're trying to do in your
'readiter' function) using an _output_ iterator.
what i would need is to get the datatype of the container which is INT
held by the back_insert_iterator.

No such thing exists. By definition nothing is _held_ by an *insert*
iterator. It inserts and moves on.
My assumption was that i would get
the iterator_traits of back_insert_iterator from function readiter ,
which would later be used to create an array or a array of pointers.

Any help appreciated?

Rethink your solution. Start by understanding what 'insert iterator'
is for.

V
 
A

anto.anish

True, i understand what you mean and back_insert_iterator does not
have a value_type coz its an output iterator.
My whole question is - is there a way to get information abt the
back_insert_iterators traits ? I undertand that its not possible. But,
is there alternate approach ?
Basically, my intention is to create an array which is of the same
data type as the container.

if i change the function readiter as below, It works how i want. But i
would be passing a type parameter.
template <class T, class T1> void readiter( T& iter, int len, T1& a)
{
T1 *tread= new T1[len];
for (int i=0;i<len;++i)
t3=i; //originally this array is populated from X
std::copy(t3, t3+ len,iter );
}

called from main as
//for int
int type1=1;
readiter(v1back,len,type1)

//for float
float type2=(float)1.0;
readiter(v1back,len,type2)

Thanks Again.
 
A

anto.anish

True, i understand what you mean and back_insert_iterator does not
have a value_type coz its an  output iterator.
My whole question is - is there a way to get information abt the
back_insert_iterators traits ? I undertand that its not possible. But,
is there alternate approach ?
Basically, my intention is to create an array which is of the same
data type as the container.

if i change the function readiter as below, It works how i want. But i
would be passing a type parameter.
template <class T, class T1> void readiter( T& iter, int len, T1& a)
{
  T1 *tread= new T1[len];
  for (int i=0;i<len;++i)
          t3=i; //originally this array is populated from X
  std::copy(t3, t3+ len,iter );

}

called from main as
//for int
int type1=1;
readiter(v1back,len,type1)

//for float
float type2=(float)1.0;
readiter(v1back,len,type2)

Thanks Again.


Hmm..i found some useful tips on dicussion abt the same topic.
http://www.adras.com/Why-no-std-back-insert-iterator-value-type.t2639-153-3.html

Thanks
Anish
 
P

Pavel

Hello,

My Requirement is
1. Copy data from iterator to an array ( array should be created
dynamically within the function based on data_type of the data
held by the iterator /container. )

2. Copy data from array into iterator ( array should be created
dynamically within the function based on data_type of the data
held by the iterator /container. )

Implementation
-----------------------
//copies data from begin to end of container to array.
template <class T>
void writeiter( T& iter1, T& iter2)
{
int t2= iter2 -iter1;
cout <<t2<<endl;
iterator_traits<T>::value_type *twrite= new
iterator_traits<T>::value_type[t2];
std::copy(iter1,iter2,twrite);
}

//copies data from array to iter (back_insert_iterator)
template <class T> void readiter( T& iter, int len)
{
//This line does not compile since return is a void.
iterator_traits<T>::value_type *tread= new
iterator_traits<T>::value_type[len]; for (int i=0; i<len;++i)
tread = i;
std::copy(tread, tread+ len,iter );
}

int main()
{
vector <int> v1;
int len=5;
back_insert_iterator< vector<int> > v1back(v1);
readiter(v1back,len); //Does not work - the function does not compile

vector<int>::iterator vbdir1=v1.begin();
vector<int>::iterator vbdir2=v1.end();
writeiter(vbdir1,vbdir2); //works good

}

The readiter function does not compile since a
iterator_trait::value_type of back_insert_iterator's returns void.
what i would need is to get the datatype of the container which is INT
held by the back_insert_iterator. My assumption was that i would get
the iterator_traits of back_insert_iterator from function readiter ,
which would later be used to create an array or a array of pointers.

Any help appreciated?

Thanks
Anish


I personally have never understood why iterator_traits::value_type is
void for output iterators: *i = t must work for some (apparently not
void) type of t so IMHO there is nothing wrong in letting client code
know this type.

Anyway, I slightly changed your code to work for me, like this:

#include <iostream>
#include <vector>
using namespace std;
template <class T>
void writeiter( T& iter1, T& iter2) {
typedef typename iterator_traits<T>::value_type ValType;
int t2= iter2 -iter1;
cout <<t2<<endl;
ValType *twrite= new ValType[t2];
std::copy(iter1,iter2,twrite);
}

template <class T> void readiter( T& iter, int len) {
typedef typename T::container_type::value_type ValType;
ValType *tread= new ValType[len];
for (int i=0; i<len;++i) tread = i;
std::copy(tread, tread+ len,iter );
}

int main() {
vector<int> v1;
int len=5;
back_insert_iterator< vector<int> > v1back(v1);
readiter(v1back,len);
vector<int>::iterator vbdir1=v1.begin();
vector<int>::iterator vbdir2=v1.end();
writeiter(vbdir1,vbdir2); //works good
}

It is certainly not a generic solution so I would rather add a second
type parameter to readIter (I know you try to avoid this) and make some
nasty comment about C++ Standard...

Another way would be to create an adapter, something like
smart_output_iterator, with template parameters for the "raw" output
iterator and for the element type, then create the specialization of
iterator_traits for this adapter. Then, you can specialize that
smart_output_iterator for ??? STL output iterators you need to use with
their peculiar ways of getting the element type (like char_type of
ostream_iterator, container_type::value_type for insert_iterator etc) --
and then use that smart_output_iterator everywhere instead of the
output_iterator. Not sure if your problem warrants all this effort for
you though..

Hope this will help

-Pavel
 
P

pelio

Victor Bazarov dixit:
My Requirement is
1. Copy data from iterator to an array ( array should be created
dynamically within the function based on data_type of the data
held by the iterator /container. )

2. Copy data from array into iterator ( array should be created
dynamically within the function based on data_type of the data
held by the iterator /container. )

Implementation
-----------------------
//copies data from begin to end of container to array.
template <class T>
void writeiter( T& iter1, T& iter2)
{
int t2= iter2 -iter1;
cout <<t2<<endl;
iterator_traits<T>::value_type *twrite= new
iterator_traits<T>::value_type[t2];
std::copy(iter1,iter2,twrite);
}

//copies data from array to iter (back_insert_iterator)
template <class T> void readiter( T& iter, int len)
{
//This line does not compile since return is a void.
iterator_traits<T>::value_type *tread= new
iterator_traits<T>::value_type[len]; for (int i=0; i<len;++i)
tread = i;
std::copy(tread, tread+ len,iter );
}

int main()
{
vector <int> v1;
int len=5;
back_insert_iterator< vector<int> > v1back(v1);
readiter(v1back,len); //Does not work - the function does not compile

vector<int>::iterator vbdir1=v1.begin();
vector<int>::iterator vbdir2=v1.end();
writeiter(vbdir1,vbdir2); //works good

}

The readiter function does not compile since a
iterator_trait::value_type of back_insert_iterator's returns void.


It doesn't "return" void.


It remind me we can do:

void f()
{
}

void g()
{
return f();
}

int main()
{
}

Unless my compiler is faulty ?
 
B

Bo Persson

True, i understand what you mean and back_insert_iterator does not
have a value_type coz its an output iterator.
My whole question is - is there a way to get information abt the
back_insert_iterators traits ? I undertand that its not possible.
But, is there alternate approach ?
Basically, my intention is to create an array which is of the same
data type as the container.

if i change the function readiter as below, It works how i want.
But i would be passing a type parameter.
template <class T, class T1> void readiter( T& iter, int len, T1&
a) {
T1 *tread= new T1[len];
for (int i=0;i<len;++i)
t3=i; //originally this array is populated from X
std::copy(t3, t3+ len,iter );

}

called from main as
//for int
int type1=1;
readiter(v1back,len,type1)

//for float
float type2=(float)1.0;
readiter(v1back,len,type2)

Thanks Again.


Hmm..i found some useful tips on dicussion abt the same topic.
http://www.adras.com/Why-no-std-back-insert-iterator-value-type.t2639-153-3.html


That only works if you really have a back_insert_iterator, not for the
more general output_iterator concept. An output_iterator could write
to a printer, for example. Then, where is your container data type? No
container?!

If you limit yourself to the template parameter being a
back_insert_iterator, then you can just use "typename
T::container_type::value_type", because you know that there must be an
underlying container. The more general iterator_traits cannot assume
that.


Bo Persson
 
B

Bo Persson

Pavel said:
I personally have never understood why iterator_traits::value_type
is void for output iterators: *i = t must work for some (apparently
not void) type of t so IMHO there is nothing wrong in letting
client code know this type.

The value_type isn't the type of t, but the possible type of *i.

The standard doesn't require that to be a C++ type, it just requires
that

*i = t;

is a legal expression. How a particular iterator implements
operator*() and operator=() on the result, isn't specified.

The iterator could write a value to the console, or a printer, or send
it over a network. Then what is the value_type?


There *could* very well be a non-void value_type, but it isn't
required.



Bo Persson
 
P

Pete Becker

True, i understand what you mean and back_insert_iterator does not
have a value_type coz its an output iterator.
My whole question is - is there a way to get information abt the
back_insert_iterators traits ? I undertand that its not possible. But,
is there alternate approach ?

On the contrary: you've gotten the information contained in the
iterator's corresponding traits class. The problem is that the traits
class doesn't have the information that you're looking for. And that,
in turn, is because iterators won't do what you're trying to do.
Basically, my intention is to create an array which is of the same
data type as the container.

You need to do this from the container. It has a member typedef named
value_type that tells you what type it holds.
 
P

Pete Becker

I personally have never understood why iterator_traits::value_type is
void for output iterators: *i = t must work for some (apparently not
void) type of t so IMHO there is nothing wrong in letting client code
know this type.

The problem is that t can have many different types for the same iterator i.

Suppose *i returns an int&. The type of t can be any arithmetic type,
and it can be any user-defined type that's convertible to an arithmetic
type. You can assign values of any of those types to an int&. There's
no single type for t.

Granted, in that case, it could be argued that the iterator's value
type should be int, because that's the type that the reference refers
to. But for more elaborate examples, that's not the case. Suppose *i
returns an object (typically called a proxy object) that has two
assignment operators. One takes an int and the other takes some
user-defined type T. Now, just as before, the type of t can be any
arithmetic type and it can be any user-defined type that's convertible
to an arithmetic type. It can also be the type T, and it can be any
type that's convertible to T. Once again, there's no single type for t,
and now there's no natural type that could be called the value type.
 
I

I V

My Requirement is ....
2. Copy data from array into iterator ( array should be created
dynamically within the function based on data_type of the data
held by the iterator /container. )

Where are you getting these requirements from? This seems like an odd
requirement. What's the point of creating an array in the function, just
to copy that array to an iterator?
Implementation
//copies data from array to iter (back_insert_iterator) template <class
T> void readiter( T& iter, int len) {
//This line does not compile since return is a void.
iterator_traits<T>::value_type *tread= new
iterator_traits<T>::value_type[len]; for (int i=0; i<len;++i)
tread = i;
std::copy(tread, tread+ len,iter );
}


First, you have a memory leak here, as tread never gets deleted. Second,
you would get the same observable effect with:

template<typename T>
void readiter(T&iter, int len)
{
for( int i = 0; i < len; ++i )
*(iter++) = i;
}

What do you want your function to do, that this function doesn't do?
 
P

Pavel

Pete said:
The problem is that t can have many different types for the same
iterator i.

Suppose *i returns an int&. The type of t can be any arithmetic type,
and it can be any user-defined type that's convertible to an arithmetic
type. You can assign values of any of those types to an int&. There's no
single type for t.

Granted, in that case, it could be argued that the iterator's value type
should be int, because that's the type that the reference refers to. But
for more elaborate examples, that's not the case. Suppose *i returns an
object (typically called a proxy object) that has two assignment
operators. One takes an int and the other takes some user-defined type
T. Now, just as before, the type of t can be any arithmetic type and it
can be any user-defined type that's convertible to an arithmetic type.
It can also be the type T, and it can be any type that's convertible to
T. Once again, there's no single type for t, and now there's no natural
type that could be called the value type.

Thanks very much Pete and Bo for taking time to answer. I believe I
understand the Standard's requirements to '*i = t' for output iterators;
what I do not understand is why it has to say that value_type is defined
as void.

We all agree that there may exist multiple types of t satisfying the
requirements to *i = t but why does it make us define value_type in a
way for which `t' of this type does not satisfy these requirements?

Is there any reason why the Standard does not allow implementations to
define value_type to *any* type satisfying the requirements to *i = t,
for example, as follows:

"In case of an output iterator, the type
iterator_traits<Iterator>::value_type is to be defined to any type for
which the requirements to to *a = t are satisfied when t is of type
iterator_traits<Iterator>::value_type"?

Then the requirements for all concrete output iterators defined in the
Standard C++ Library could narrow down this requirement (for example, as
per my previous post). Basically, the very fact that *all* concrete
output iterators in the Library allow the client to figure out some
related (and unique) "value type" indirectly proves this use case covers
some considerable base (hate to take numbers out of thin air, but here,
I would argue for more than 70%); and for the rest of the use cases, I
do not see how the above requirement could harm their cause even though
it might not help either.

As it is now, it is difficult to answer the original question and people
seem to try to attack the requirements behind it (which IMHO are or can
be made valid and general enough to warrant an answer).

Regards,
-Pavel
 
B

Bo Persson

Pavel said:
Thanks very much Pete and Bo for taking time to answer. I believe I
understand the Standard's requirements to '*i = t' for output
iterators; what I do not understand is why it has to say that
value_type is defined as void.

We all agree that there may exist multiple types of t satisfying the
requirements to *i = t but why does it make us define value_type in
a way for which `t' of this type does not satisfy these
requirements?

Output iterators work kind of backwards. There is no requirement that
't' should be of any particular type, just that it should be
convertible to the type of '*i'. It could be that 't' is a class with
several conversion operators, or there could be several assignment
operators available for different types, or the actual type of '*i'
could have several converting constructors. It is not always possible
to catch that in a single typedef.

If you want to, you can overload std::iterator_traits for one of you
own output iterators with a non-void value_type, but the standard just
doesn't require the standard iterators to do that. Because sometime it
is just not possible.


Bo Persson
 
A

anto.anish

Output iterators work kind of backwards. There is no requirement that
't' should be of any particular type, just that it should be
convertible to the type of '*i'. It could be that 't' is a class with
several conversion operators, or there could be several assignment
operators available for different types, or the actual type of '*i'
could have several converting constructors. It is not always possible
to catch that in a single typedef.

If you want to, you can overload std::iterator_traits for one of you
own output iterators with a non-void value_type, but the standard just
doesn't require the standard iterators to do that. Because sometime it
is just not possible.

Bo Persson- Hide quoted text -

- Show quoted text -

Thanks Pavel, Bo, Pete and Victor for all your inputs and valuable
comments.

Pavel, Bo
I think i can live with by using value_type of the container for
time being, i understand from your comments that
this is not a generic implementation for general iterator_traits.
let me also try out your second solution
of an adaptor.

Pete,

yes, you are correct. I could use *(iter++)=i.
However the data written to iter is not always an int as i wrote.
The data to be returned is actually
read and returned from HDF5 file as buffer. Hence i need to create a
temp holding array of the type
that the container was created from, to which i can copy the entire
return buf;
Yep, I need to add a delete ( I knew everyone would note this:) ).

Thanks
Anish
 
T

Triple-DES

On 8 Feb, 23:47, (e-mail address removed) wrote:
[snip]
what i would need is to get the datatype of the container which is INT
held by the back_insert_iterator. My assumption was that i would get
the iterator_traits of back_insert_iterator from function readiter ,
which would later be used to create an array or a array of pointers.

Any help appreciated?

I am unsure what you are trying to accomplish. But you can create an
array of the type of the container of the back_insert_iterator using
something like this:

template<typename BackInserter>
void f(BackInserter& bi)
{
typedef BackInserter::container_type::value_type T;
T * t = new T[42];
}
 

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

Staff online

Members online

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,045
Latest member
DRCM

Latest Threads

Top