C++ Primer ex 9.14

A

arnuld

/* 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 ?
 
G

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 ?

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)
);
 
A

arnuld

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


;-)
 
A

arnuld

~/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;
}
 
B

Barry

Erik said:
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)
 
J

James Kanze

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

Barry

James said:
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.
 
J

James Kanze

^ ^
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:
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.)
 
B

Barry

James Kanze 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
 
J

James Kanze

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:

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

arnuld

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)
 

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

Similar Threads

C++ Primer ex 3.14 8
C++ Primer ex 5.18 5
C++ Primer ex 6.20 36
C++ Primer ex 9.27 4
C++ Primer ex 7.14 2
counting words in input 16
C++ Primer ex 9.34, using a Stack 1
Crossword 2

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,904
Latest member
HealthyVisionsCBDPrice

Latest Threads

Top