C++ Primer ex 9.14

Discussion in 'C++' started by arnuld, Sep 16, 2007.

  1. arnuld

    arnuld Guest

    /* C++ Primer - 4/e
    *
    * STATEMENT
    * write a program to read sequence of strings from the standard
    * input into a vector. Print the vector.
    *
    */

    #include <iostream>
    #include <string>
    #include <vector>
    #include <iterator>

    int main()
    {
    std::vector<std::string> svec;
    std::string word;

    while( std::cin >> word )
    {
    svec.push_back( word );
    }

    /* print the vector */
    std::cout << "\n\n----- You Entered -------\n\n";
    std::copy( svec.begin(), svec.end(),
    std::eek:stream_iterator<std::string>( std::cout, "\n" ) );


    return 0;
    }


    It runs fine. Is there any way I can replace what while loop with
    std::copy ?

    --
    http://lispmachine.wordpress.com
     
    arnuld, Sep 16, 2007
    #1
    1. Advertising

  2. On 2007-09-16 12:43, arnuld wrote:
    > /* C++ Primer - 4/e
    > *
    > * STATEMENT
    > * write a program to read sequence of strings from the standard
    > * input into a vector. Print the vector.
    > *
    > */
    >
    > #include <iostream>
    > #include <string>
    > #include <vector>
    > #include <iterator>
    >
    > int main()
    > {
    > std::vector<std::string> svec;
    > std::string word;
    >
    > while( std::cin >> word )
    > {
    > svec.push_back( word );
    > }
    >
    > /* print the vector */
    > std::cout << "\n\n----- You Entered -------\n\n";
    > std::copy( svec.begin(), svec.end(),
    > std::eek:stream_iterator<std::string>( std::cout, "\n" ) );
    >
    >
    > return 0;
    > }
    >
    >
    > It runs fine. Is there any way I can replace what while loop with
    > std::copy ?


    Might be, you would have to use std::istream_iterators and a back insert
    iterator to add the elements to the vector, something like (untested):

    std::copy(
    std::istream_iterator<std::string>(std::cin),
    std::istream_iterator<std::string>() // The same as end() for a stream
    std::back_insert_iterator<std::vector>(vec)
    );

    --
    Erik Wikström
     
    =?UTF-8?B?RXJpayBXaWtzdHLDtm0=?=, Sep 16, 2007
    #2
    1. Advertising

  3. arnuld

    arnuld Guest

    > On Sun, 16 Sep 2007 11:02:15 +0000, Erik Wikström wrote:
    > Might be, you would have to use std::istream_iterators and a back insert
    > iterator to add the elements to the vector, something like (untested):
    >
    > std::copy(
    > std::istream_iterator<std::string>(std::cin),
    > std::istream_iterator<std::string>() // The same as end() for a stream
    > std::back_insert_iterator<std::vector>(vec)
    > );



    it works:

    std::copy( std::istream_iterator<std::string>( std::cin ),
    std::istream_iterator<std::string>(),
    std::back_insert_iterator<std::vector<std::string> >( svec ) );

    ~/programming/c++ $ g++ -ansi -pedantic -Wall -Wextra ex_09-14.cpp
    ~/programming/c++ $ ./a.out
    Erik Wikstrom Helps arnuld


    ----- You Entered -------

    Erik
    Wikstrom
    Helps
    arnuld
    ~/programming/c++ $


    ;-)

    --
    http://lispmachine.wordpress.com
     
    arnuld, Sep 16, 2007
    #3
  4. arnuld

    arnuld Guest

    > On Sun, 16 Sep 2007 16:38:22 +0500, arnuld wrote:

    > ~/programming/c++ $ g++ -ansi -pedantic -Wall -Wextra ex_09-14.cpp
    > ~/programming/c++ $ ./a.out
    > Erik Wikstrom Helps arnuld
    >
    >
    > ----- You Entered -------
    >
    > Erik
    > Wikstrom
    > Helps
    > arnuld
    > ~/programming/c++ $
    >
    >
    > ;-)


    even the same programme works for std::list:

    /* C++ Primer - 4/e
    *
    * STATEMENT
    * write a program to read sequence of strings from the standard
    * input into a list. Print the list.
    *
    */

    #include <iostream>
    #include <string>
    #include <list>
    #include <iterator>

    int main()
    {
    std::list<std::string> slist;
    std::string word;

    /*
    while( std::cin >> word )
    {
    svec.push_back( word );
    }
    */

    std::copy( std::istream_iterator<std::string>( std::cin ),
    std::istream_iterator<std::string>(),
    std::back_insert_iterator<std::list<std::string> >( slist ) );


    /* print the vector */
    std::cout << "\n\n----- You Entered -------\n\n";
    std::copy( slist.begin(), slist.end(),
    std::eek:stream_iterator<std::string>( std::cout, "\n" ) );


    return 0;
    }


    --
    http://lispmachine.wordpress.com
     
    arnuld, Sep 16, 2007
    #4
  5. arnuld

    Barry Guest

    Erik Wikström wrote:
    > On 2007-09-16 12:43, arnuld wrote:
    >> /* C++ Primer -
    >> 4/e
    >> *
    >> *
    >> STATEMENT
    >> * write a program to read sequence of strings from the
    >> standard *
    >> input into a vector. Print the
    >> vector.
    >> *
    >> */
    >>
    >> #include
    >> <iostream>
    >> #include
    >> <string>
    >> #include
    >> <vector>
    >> #include
    >> <iterator>
    >>
    >> int
    >> main()
    >> {
    >> std::vector<std::string>
    >> svec;
    >> std::string
    >> word;
    >>
    >> while( std::cin >> word
    >> )
    >>
    >> {
    >> svec.push_back( word
    >> );
    >>
    >> }
    >>
    >> /* print the vector
    >> */
    >> std::cout << "\n\n----- You Entered
    >> -------\n\n";
    >> std::copy( svec.begin(),
    >> svec.end(),
    >> std::eek:stream_iterator<std::string>( std::cout, "\n" )
    >> );
    >>
    >>
    >> return
    >> 0;
    >> }
    >>
    >> It runs fine. Is there any way I can replace what while loop with
    >> std::copy ?

    >
    > Might be, you would have to use std::istream_iterators and a back insert
    > iterator to add the elements to the vector, something like (untested):
    >
    > std::copy(
    > std::istream_iterator<std::string>(std::cin),
    > std::istream_iterator<std::string>() // The same as end() for a stream
    > std::back_insert_iterator<std::vector>(vec)


    std::back_insert_iterator<std::vector<std::string> >(vec)

    or just simply use adapter, which is more straightforward

    std::back_inserter(vec)

    > );
    >



    --
    Thanks
    Barry
     
    Barry, Sep 16, 2007
    #5
  6. arnuld

    arnuld Guest

    > On Sun, 16 Sep 2007 20:43:21 +0800, Barry wrote:

    > or just simply use adapter, which is more straightforward
    >
    > std::back_inserter(vec)


    cool... :cool:

    --
    http://lispmachine.wordpress.com
     
    arnuld, Sep 16, 2007
    #6
  7. arnuld

    James Kanze Guest

    On Sep 16, 1:02 pm, Erik Wikström <> wrote:
    [...]
    > > It runs fine. Is there any way I can replace what while loop with
    > > std::copy ?


    > Might be, you would have to use std::istream_iterators and a back insert
    > iterator to add the elements to the vector, something like (untested):


    > std::copy(
    > std::istream_iterator<std::string>(std::cin),
    > std::istream_iterator<std::string>() // The same as end() for a stream
    > std::back_insert_iterator<std::vector>(vec)
    > );


    Even simpler would be to use the istream_iterators to initialize
    the container. Something like:

    std::vector< std::string > vec(
    (std::istream_iterator< std::string >( std::cin )),
    (std::istream_iterator< std::string >()) ) ;

    (Note that the outermost parentheses around the arguments are
    necessary to prevent the compiler from interpreting the
    statement as a function declaration.)

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, Sep 16, 2007
    #7
  8. arnuld

    Barry Guest

    James Kanze wrote:
    > On Sep 16, 1:02 pm, Erik Wikström <> wrote:
    > [...]
    >>> It runs fine. Is there any way I can replace what while loop with
    >>> std::copy ?

    >
    >> Might be, you would have to use std::istream_iterators and a back insert
    >> iterator to add the elements to the vector, something like (untested):

    >
    >> std::copy(
    >> std::istream_iterator<std::string>(std::cin),
    >> std::istream_iterator<std::string>() // The same as end() for a stream
    >> std::back_insert_iterator<std::vector>(vec)
    >> );

    >
    > Even simpler would be to use the istream_iterators to initialize
    > the container. Something like:
    >
    > std::vector< std::string > vec(
    > (std::istream_iterator< std::string >( std::cin )),

    ^ ^
    if it's not for formatting, then it's
    not necessary as std::cin is not a type,


    > (std::istream_iterator< std::string >()) ) ;
    >
    > (Note that the outermost parentheses around the arguments are
    > necessary to prevent the compiler from interpreting the
    > statement as a function declaration.)


    and it's not a function declaration I think. As "TypeA ()" is a function
    type who returns "TypeA". So if the compiler wrongly interpret this way,
    then it will report that "passing a type is illegal" (I just made this
    wording :) )

    >


    it only happens to those with none parameter like the latter one you wrote.

    --
    Thanks
    Barry
     
    Barry, Sep 17, 2007
    #8
  9. arnuld

    James Kanze Guest

    On Sep 17, 3:42 am, Barry <> wrote:
    > James Kanze wrote:
    > > On Sep 16, 1:02 pm, Erik Wikström <> wrote:
    > > [...]
    > >>> It runs fine. Is there any way I can replace what while loop with
    > >>> std::copy ?


    > >> Might be, you would have to use std::istream_iterators and a back insert
    > >> iterator to add the elements to the vector, something like (untested):


    > >> std::copy(
    > >> std::istream_iterator<std::string>(std::cin),
    > >> std::istream_iterator<std::string>() // The same as end() for a stream
    > >> std::back_insert_iterator<std::vector>(vec)
    > >> );


    > > Even simpler would be to use the istream_iterators to initialize
    > > the container. Something like:


    > > std::vector< std::string > vec(
    > > (std::istream_iterator< std::string >( std::cin )),


    > ^ ^
    > if it's not for formatting, then it's
    > not necessary as std::cin is not a type,


    I'm not sure. You may be right, because I don't think that
    std::cin is a legal variable name in this context. But the more
    frequent:
    (std::istream_iterator< std::string >( input )),
    does require them.

    > > (std::istream_iterator< std::string >()) ) ;


    > > (Note that the outermost parentheses around the arguments are
    > > necessary to prevent the compiler from interpreting the
    > > statement as a function declaration.)


    > and it's not a function declaration I think. As "TypeA ()" is
    > a function type who returns "TypeA". So if the compiler
    > wrongly interpret this way, then it will report that "passing
    > a type is illegal" (I just made this wording :) )


    > it only happens to those with none parameter like the latter
    > one you wrote.


    std::istream_iterator< std::string >()

    would be a declaration---in the context of a function parameter,
    it's the equivalent of:
    std::istream_iterator< std::string >(*ptrToFnc)()
    And while I think you're right for
    std::istream_iterator< std::string >( std::cin ),
    something like:
    std::istream_iterator< std::string >( someFile ),
    is definitely a declaration.

    Technically, too, it should be sufficient to disambiguate any
    one of the parameters; adding the parentheses to just one of the
    parameters should suffice. But I've had problems with this in
    the past, and have gotten into the habit of adding them more or
    less systematically, whenever there might be an ambiguity.

    (This is really something that needs fixing, although I don't
    have a good solution. Imagine the poor beginner, who originally
    writes the code without the extra parentheses, using std::cin,
    and it works fine. He then replaces std::cin with a file, and
    suddenly gets compiler errors when he tries to use vec, further
    down in his code.)

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, Sep 17, 2007
    #9
  10. arnuld

    Barry Guest

    James Kanze wrote:


    >> it only happens to those with none parameter like the latter
    >> one you wrote.

    >
    > std::istream_iterator< std::string >()
    >
    > would be a declaration---in the context of a function parameter,


    declaration of what?
    a function or a pointer to function?

    I think this needs more discussion:

    see:

    template <class F = void()>
    struct Func;

    template <class RET, class ARG>
    struct Func <RET(ARG)>
    {
    };

    Func<int(int)> int_int_f;

    here "int(int)" is a type I think, not a variable.

    If you say "it differs if context differs", would you tell me more?


    > it's the equivalent of:
    > std::istream_iterator< std::string >(*ptrToFnc)()


    actually, they are not equivent

    int (f)(int); : f is typeof function
    int (*pf) (int); : pf is typeof pointer to function.

    > And while I think you're right for
    > std::istream_iterator< std::string >( std::cin ),
    > something like:
    > std::istream_iterator< std::string >( someFile ),
    > is definitely a declaration.
    >
    > Technically, too, it should be sufficient to disambiguate any
    > one of the parameters; adding the parentheses to just one of the
    > parameters should suffice. But I've had problems with this in
    > the past, and have gotten into the habit of adding them more or
    > less systematically, whenever there might be an ambiguity.


    yeh, it depends on the compiler, I think, though I don't use many compilers.

    maybe adding "()" around the variable is still not the ultimate
    solution, it *may* (I don't have any test case) still fail to compile on
    some compilers.

    the most portable way, but not so elegant would be

    std::istream_iterator< std::string > end;

    vector<...> vec(
    ...
    end
    );


    >
    > (This is really something that needs fixing, although I don't
    > have a good solution. Imagine the poor beginner, who originally
    > writes the code without the extra parentheses, using std::cin,
    > and it works fine. He then replaces std::cin with a file, and
    > suddenly gets compiler errors when he tries to use vec, further
    > down in his code.)
    >


    :), considerate

    --
    Thanks
    Barry
     
    Barry, Sep 17, 2007
    #10
  11. arnuld

    James Kanze Guest

    On Sep 17, 11:11 am, Barry <> wrote:
    > James Kanze wrote:
    > >> it only happens to those with none parameter like the latter
    > >> one you wrote.


    > > std::istream_iterator< std::string >()


    > > would be a declaration---in the context of a function parameter,


    > declaration of what?
    > a function or a pointer to function?


    Yes:).

    The declaration:
    std::istream_iterator< std::string > toto() ;
    declares a function, with the name toto. As a function
    parameter, the name is optional (so we end up with
    "std::istream_iterator< std::string >()", AND "After determining
    the type of each parameter, any parameter of type 'array of T'
    or 'function returning T' is adjusted to be 'pointer to T' or
    'pointer to function returning T,' respectively" (§8.3.5/3).

    A horrible misfeature, inherited from C, but one we have to live
    with.

    > I think this needs more discussion:


    > see:


    > template <class F = void()>
    > struct Func;


    > template <class RET, class ARG>
    > struct Func <RET(ARG)>
    > {
    > };


    > Func<int(int)> int_int_f;


    > here "int(int)" is a type I think, not a variable.


    Certainly. It matches a template type argument. It can only be
    a type. A non-type wouldn't be legal in this context.

    > If you say "it differs if context differs", would you tell me more?


    See above. A function is a perfectly valid type. But not as a
    function parameter. In a function declaration, function types
    behave much like array types; they are adjusted to pointer to
    function. (Note that in general, too, an expression of type
    function will be implicitly converted to a pointer to function,
    unless it is the operand of a () operator.)

    > > it's the equivalent of:
    > > std::istream_iterator< std::string >(*ptrToFnc)()


    > actually, they are not equivent


    As a function parameter, they are exactly the same.

    > int (f)(int); : f is typeof function
    > int (*pf) (int); : pf is typeof pointer to function.


    > > And while I think you're right for
    > > std::istream_iterator< std::string >( std::cin ),
    > > something like:
    > > std::istream_iterator< std::string >( someFile ),
    > > is definitely a declaration.


    > > Technically, too, it should be sufficient to disambiguate any
    > > one of the parameters; adding the parentheses to just one of the
    > > parameters should suffice. But I've had problems with this in
    > > the past, and have gotten into the habit of adding them more or
    > > less systematically, whenever there might be an ambiguity.


    > yeh, it depends on the compiler, I think, though I don't use
    > many compilers.


    Note that I'm not aware of a modern compiler which has this
    problem. G++ had it for a long time, however, and I've gotten
    into the habit of programming against it. (Also, I prefer
    orthogonality.)

    > maybe adding "()" around the variable is still not the
    > ultimate solution, it *may* (I don't have any test case) still
    > fail to compile on some compilers.


    > the most portable way, but not so elegant would be


    > std::istream_iterator< std::string > end;


    > vector<...> vec(
    > ...
    > end
    > );


    Introducing an additional named variable? That makes sense when
    the name adds some significant semantic information, but the two
    iterator idiom is so ubiquious that this isn't the case here.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, Sep 18, 2007
    #11
  12. arnuld

    arnuld Guest

    you guys are talking of alien life on Mars :p

    (actually, I was only able to understand a little more than 1/3rd of
    it)
     
    arnuld, Sep 18, 2007
    #12
    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. Richard

    SSL / authentication primer

    Richard, Jul 25, 2003, in forum: Java
    Replies:
    2
    Views:
    487
    Richard
    Jul 25, 2003
  2. Chris
    Replies:
    0
    Views:
    374
    Chris
    Apr 18, 2005
  3. Captain Dondo

    SVG primer

    Captain Dondo, Jan 21, 2006, in forum: HTML
    Replies:
    1
    Views:
    586
    Toby Inkster
    Jan 22, 2006
  4. Charles L

    'C++ Primer 2nd Ed' errata

    Charles L, Apr 11, 2004, in forum: C++
    Replies:
    2
    Views:
    370
  5. hugo
    Replies:
    1
    Views:
    372
    Ali Cehreli
    Aug 17, 2004
Loading...

Share This Page