value_type of a back_insert_iterator

C

Chyi Pin Lim

Why is the type for back_insert_iterator void and not the type of its
encapsulating container?

Why:

namespace std {

template<class Category, class T, class Distance = ptrdiff_t,
class Pointer = T*, class Reference = T&> struct
iterator;

template <class Container>
class back_insert_iterator :
public iterator<output_iterator_tag,void,void,void,void> {
protected:
Container* container;
// -- removed for clarity
};
}

Instead of:

template <class Container>
class back_insert_iterator :
public iterator<output_iterator_tag, typename
Container::value_type,void,void,void> {
protected:
Container* container;
// -- removed for clarity
};
 
P

P.J. Plauger

Why is the type for back_insert_iterator void and not the type of its
encapsulating container?

Because it's an output iterator, which is a pure sink. (You can't
peek at any of the things stored in the sequence it controls.)

P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com
 
C

Chyi Pin Lim

P.J. Plauger said:
Because it's an output iterator, which is a pure sink. (You can't
peek at any of the things stored in the sequence it controls.)

P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com

True that I can't peek, but in inserting a value, wouldn't it be
beneficial to know the type in case someone wants to use parameterized
constructor / enforce parameterized contruction.

What I meant is as follows:

// following std::copy
template <typename InIt, typename OutIt>
OutIt copy_to_container(InIt begin, InIt end, OutIt result)
{
// want to use value_type for output
*result = OutIt::value_type(begin, end);
return ++result;
}

Using append:

char s[] = "abc";
vector<string> vs(1); // contain 1 string
vector<vector<char> > vvc(1);

copy_to_container(s, s+1, vs.begin()); // ok
copy_to_container(s, s+1, vvc.begin()); // ok
copy_to_container(s, s+2, back_inserter(vs)); // fail to compile


If the value_type of back_inserter is defined as the type of its
encapsulating container, we can utilize that property.

Since this is not possible, please advise on alternative
implementation that is as flexible.
 
P

P.J. Plauger

"P.J. Plauger" <[email protected]> wrote in message

True that I can't peek, but in inserting a value, wouldn't it be
beneficial to know the type in case someone wants to use parameterized
constructor / enforce parameterized contruction.

It might be, but that's not a requirement for output iterators.
What I meant is as follows:

// following std::copy
template <typename InIt, typename OutIt>
OutIt copy_to_container(InIt begin, InIt end, OutIt result)
{
// want to use value_type for output
*result = OutIt::value_type(begin, end);

Shouldn't there be a loop in here somewhere?
return ++result;
}

Using append:

char s[] = "abc";
vector<string> vs(1); // contain 1 string
vector<vector<char> > vvc(1);

copy_to_container(s, s+1, vs.begin()); // ok
copy_to_container(s, s+1, vvc.begin()); // ok
copy_to_container(s, s+2, back_inserter(vs)); // fail to compile


If the value_type of back_inserter is defined as the type of its
encapsulating container, we can utilize that property.

Since this is not possible, please advise on alternative
implementation that is as flexible.

If you want to use additional type information to constrain
assignments to an output iterator, you'll have to supply it
by a different channel.

P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com
 
P

ppLiu_china

I agree with P.J.Plauger

What I thought is:
if an output iterator exposes its value_type to the user,then someone
who use it like this:
template<typename OutIte>
void f(OutIte ite){
OutIte::value_type value=*ite; //should it be compiled??
...
}
will expect that such a function can be compiled,which exactly can't
be(you can't get the value that refered to by an output iterator).
Now consider what really happened here:
users thought that 'operator *' returns a value of 'value_type',so if
the 'value_type' was some concrete class or primitive type,the
function template above should be compiled according to the semantic
it has.

of course you can let 'operator *' returns a no-meaning value of a
no-meaning type,such as a proxy,or *this(as the ostream_iterator
actually did),but note that what the value_type is,it isn't the return
type of 'operator *',
So it's inconsistent!!!!

But by declaring the value_type as 'void',it can avoid this kind of
inconsistent----because *ite returns 'void',so you actually can't
cache it anywhere.In other ways,the 'void' value_type implies that you
actually coudn't get the value_type,and you shouldn't care about it
either.With that being the case,you can write "*ite=value".
What really important is semantic.

The situation that you present may rarely happen,I think.
If it happened,like P.J.Plauger said,you'll have to supply it
by a different channel.
 
C

Chyi Pin Lim

P.J. Plauger said:
It might be, but that's not a requirement for output iterators.


Shouldn't there be a loop in here somewhere?

No loop here, result is a container of a container, and I want to copy
elements from begin to end as an element of result. The examples
shows the usage (this is just a simplification).
return ++result;
}

Using append:

char s[] = "abc";
vector<string> vs(1); // contain 1 string
vector<vector<char> > vvc(1);

copy_to_container(s, s+1, vs.begin()); // ok
copy_to_container(s, s+1, vvc.begin()); // ok
copy_to_container(s, s+2, back_inserter(vs)); // fail to compile


If the value_type of back_inserter is defined as the type of its
encapsulating container, we can utilize that property.

Since this is not possible, please advise on alternative
implementation that is as flexible.

If you want to use additional type information to constrain
assignments to an output iterator, you'll have to supply it
by a different channel.

Naturally, the solution I came up w/ is to derived
back_insert_with_type from back_inserter and define the value_type as
the type of the container. Please give your opinion on this solution.
If possible, please provide ideas for alternative solutions to my
problem. Thanks.
 
C

Chyi Pin Lim

Thank you for posting such a descriptive explanation.
What I thought is:
if an output iterator exposes its value_type to the user,then someone
who use it like this:
template<typename OutIte>
void f(OutIte ite){
OutIte::value_type value=*ite; //should it be compiled??
...
}
will expect that such a function can be compiled,which exactly can't
be(you can't get the value that refered to by an output iterator).
Now consider what really happened here:
users thought that 'operator *' returns a value of 'value_type',so if
the 'value_type' was some concrete class or primitive type,the
function template above should be compiled according to the semantic
it has.

As an output iterator, it is expected that one should not read
from it, but allow to write to the iterator. As such,
OutIt::value_type value = *it; // should not compile
however,
I was thinking,
OutIt::value_type value = *in_it; // if *in_it is convertible to
OutIt::value_type, then it should allow to compile
*out_it = value; // ok
of course you can let 'operator *' returns a no-meaning value of a
no-meaning type,such as a proxy,or *this(as the ostream_iterator
actually did),but note that what the value_type is,it isn't the return
type of 'operator *',
So it's inconsistent!!!!

But by declaring the value_type as 'void',it can avoid this kind of
inconsistent----because *ite returns 'void',so you actually can't
cache it anywhere.In other ways,the 'void' value_type implies that you
actually coudn't get the value_type,and you shouldn't care about it
either.With that being the case,you can write "*ite=value".
What really important is semantic.

I see your point and agree w/ your argument. However, defining
the value_type as the type of the container doesn't break the semantic
usage.

we still do not allow:
OutIt::value_type v = *out_it;
but allow:
*out_it = v;
 
P

P.J. Plauger

Naturally, the solution I came up w/ is to derived
back_insert_with_type from back_inserter and define the value_type as
the type of the container. Please give your opinion on this solution.
If possible, please provide ideas for alternative solutions to my
problem. Thanks.

That sounds like one version of the solution I suggested. Go with it.

P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com
 
P

ppLiu_china

we still do not allow:
OutIt::value_type v = *out_it;
but allow:
*out_it = v;

Really?Consider the ostream_iterator<>,which typically is implemented as following:
//coped from STL of VC.NET
template<...>
class ostream_iterator{
public:
ostream_iterator<_Ty, _Elem, _Traits>& operator*()
{
return (*this); //note the return type
}
}
and give you a simply class:
class Swap
{
public:
Swap(const ostream_iterator<Swap>&){} #1
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //note the parameter type
...
};
Now,Consider the following code:
int main()
{
...
ostream_iterator<Swap> os_ite=someOstream.begin(); //we will read 'Swap'
//from 'someOstream'
ostream_iterator<Swap>::value_type value =
*os_ite; #2 //if the 'value_type'
//is 'Swap',what will
//happen here?
return 0;
}
At #2,if 'value_type' was defined as Swap,then #2 is the same as:
Swap value=*os_ite; #3
But,*os_ite returns a reference to itself,that is ostream_iterator<Swap>&,which
was then used as the parameter type of Swap's constructor(see #1);

So compiler will let #3 go!
Is that what we want?

By defining value_type as 'void'(a type that means 'nothing'),we can avoid this.
 

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

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,575
Members
45,053
Latest member
billing-software

Latest Threads

Top