value_type of a back_insert_iterator

Discussion in 'C++' started by Chyi Pin Lim, Dec 5, 2003.

  1. Chyi Pin Lim

    Chyi Pin Lim Guest

    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
    };
     
    Chyi Pin Lim, Dec 5, 2003
    #1
    1. Advertising

  2. Chyi Pin Lim

    P.J. Plauger Guest

    "Chyi Pin Lim" <> wrote in message
    news:...

    > 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
     
    P.J. Plauger, Dec 5, 2003
    #2
    1. Advertising

  3. Chyi Pin Lim

    Chyi Pin Lim Guest

    "P.J. Plauger" <> wrote in message news:<kA8Ab.354$>...
    > "Chyi Pin Lim" <> wrote in message
    > news:...
    >
    > > 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


    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.
     
    Chyi Pin Lim, Dec 6, 2003
    #3
  4. Chyi Pin Lim

    P.J. Plauger Guest

    "Chyi Pin Lim" <> wrote in message
    news:...

    > "P.J. Plauger" <> wrote in message

    news:<kA8Ab.354$>...
    > > "Chyi Pin Lim" <> wrote in message
    > > news:...
    > >
    > > > 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

    >
    > 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.J. Plauger, Dec 6, 2003
    #4
  5. Chyi Pin Lim

    ppLiu_china Guest

    "P.J. Plauger" <> wrote in message news:<kA8Ab.354$>...
    > "Chyi Pin Lim" <> wrote in message
    > news:...
    >
    > > 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

    I agree with P.J.Plauger
     
    ppLiu_china, Dec 6, 2003
    #5
  6. Chyi Pin Lim

    ppLiu_china Guest

    (ppLiu_china) wrote in message news:<>...
    > "P.J. Plauger" <> wrote in message news:<kA8Ab.354$>...
    > > "Chyi Pin Lim" <> wrote in message
    > > news:...
    > >
    > > > 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

    > 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.
     
    ppLiu_china, Dec 7, 2003
    #6
  7. Chyi Pin Lim

    Chyi Pin Lim Guest

    "P.J. Plauger" <> wrote in message news:<VKhAb.1919$%>...
    > "Chyi Pin Lim" <> wrote in message
    > news:...
    >
    > > "P.J. Plauger" <> wrote in message

    > news:<kA8Ab.354$>...
    > > > "Chyi Pin Lim" <> wrote in message
    > > > news:...
    > > >
    > > > > 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

    > >
    > > 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?


    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.
     
    Chyi Pin Lim, Dec 8, 2003
    #7
  8. Chyi Pin Lim

    Chyi Pin Lim Guest

    Thank you for posting such a descriptive explanation.

    > > >
    > > > > 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

    > > 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.


    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;

    > 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.
     
    Chyi Pin Lim, Dec 8, 2003
    #8
  9. Chyi Pin Lim

    P.J. Plauger Guest

    "Chyi Pin Lim" <> wrote in message
    news:...

    > > > 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.


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

    P.J. Plauger
    Dinkumware, Ltd.
    http://www.dinkumware.com
     
    P.J. Plauger, Dec 8, 2003
    #9
  10. Chyi Pin Lim

    ppLiu_china Guest

    > 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.
     
    ppLiu_china, Dec 11, 2003
    #10
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. chris
    Replies:
    8
    Views:
    518
    Tom Widmer
    Dec 10, 2004
  2. cesco
    Replies:
    5
    Views:
    388
    Maxim Yegorushkin
    Feb 10, 2006
  3. Andrew
    Replies:
    4
    Views:
    390
    Victor Bazarov
    Mar 7, 2006
  4. Replies:
    14
    Views:
    1,394
    Triple-DES
    Feb 12, 2008
  5. Rares Vernica
    Replies:
    2
    Views:
    333
    Jerry Coffin
    Jun 21, 2008
Loading...

Share This Page