Connecting Tech Pros Worldwide Help | Site Map

Using copy for output

  #1  
Old December 6th, 2006, 08:13 PM
Paulo Matos
Guest
 
Posts: n/a
Hi all,

Given a list of int, it's rather easy to output them line by line:
std::copy(mylist.begin(), mylist.end(),
std::ostream_iterator<int>(cout, "\n");

Now, there's two ways in which I would like to generalize this:
First, I would like to be able to print a list of pointers to int.
However, I'm guessing this is not possible with copy, right?
I would have to:
for(std::list<int>::const_iterator it = mylist.begin(); it !=
mylist.end() ; ++it) cout << **it << "\n";

Right? Not possible with copy?
Another thing I would like to do it to had a character in-between each
printed int. For example:
If I have a list with 1,2,3,4,5 and I want to print " + " I would get 1
+ 2 + 3 + 4 + 5.
A solution is:
std::string str(" + ");
for(std::list<int>::const_iterator it = mylist.begin(); it !=
mylist.end() ; ++it) {
cout << **it;
std::list<int>::const_iterator aux = it;
if(++aux != mylist.end())
cout << str;
}

Is there any better way? Comments on this? Anyway to do this more
straightforwardly?

Regards,

Paulo Matos

  #2  
Old December 6th, 2006, 08:13 PM
Pete Becker
Guest
 
Posts: n/a

re: Using copy for output


Paulo Matos wrote:
Quote:
If I have a list with 1,2,3,4,5 and I want to print " + " I would get 1
+ 2 + 3 + 4 + 5.
std::copy(mylist.begin(), mylist.end(),
std::ostream_iterator<int>(cout, " + ");

--

-- Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com)
Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." (www.petebecker.com/tr1book)
  #3  
Old December 6th, 2006, 08:45 PM
Paulo Matos
Guest
 
Posts: n/a

re: Using copy for output



Pete Becker escreveu:
Quote:
Paulo Matos wrote:
Quote:
If I have a list with 1,2,3,4,5 and I want to print " + " I would get 1
+ 2 + 3 + 4 + 5.
>
std::copy(mylist.begin(), mylist.end(),
std::ostream_iterator<int>(cout, " + ");
>
That's what's I did iintially with '\n' however, it's not the same
thing. The result of that is:
1 + 2 + 3 + 4 + 5 +

And I don't want the extra plus in the end. What about if the list
contains pointers to ints?
Quote:
--
>
-- Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com)
Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." (www.petebecker.com/tr1book)
  #4  
Old December 6th, 2006, 09:15 PM
Roland Pibinger
Guest
 
Posts: n/a

re: Using copy for output


On 6 Dec 2006 13:05:01 -0800, "Paulo Matos" wrote:
Quote:
>Pete Becker escreveu:
Quote:
>Paulo Matos wrote:
Quote:
If I have a list with 1,2,3,4,5 and I want to print " + " I would get 1
+ 2 + 3 + 4 + 5.
>>
>std::copy(mylist.begin(), mylist.end(),
>std::ostream_iterator<int>(cout, " + ");
>
>That's what's I did iintially with '\n' however, it's not the same
>thing. The result of that is:
>1 + 2 + 3 + 4 + 5 +
>
>And I don't want the extra plus in the end.
add:

cout << "\b\b\b"; // works for some ostreams
Quote:
>What about if the list contains pointers to ints?
I'd use a for loop anyway. copy is 'semantically' wrong for output.

Best wishes,
Roland Pibinger

  #5  
Old December 6th, 2006, 10:35 PM
Salt_Peter
Guest
 
Posts: n/a

re: Using copy for output



Paulo Matos wrote:
Quote:
Hi all,
>
Given a list of int, it's rather easy to output them line by line:
std::copy(mylist.begin(), mylist.end(),
std::ostream_iterator<int>(cout, "\n");
>
Now, there's two ways in which I would like to generalize this:
First, I would like to be able to print a list of pointers to int.
However, I'm guessing this is not possible with copy, right?
I would have to:
for(std::list<int>::const_iterator it = mylist.begin(); it !=
mylist.end() ; ++it) cout << **it << "\n";
>
Right? Not possible with copy?
Another thing I would like to do it to had a character in-between each
printed int. For example:
If I have a list with 1,2,3,4,5 and I want to print " + " I would get 1
+ 2 + 3 + 4 + 5.
A solution is:
std::string str(" + ");
for(std::list<int>::const_iterator it = mylist.begin(); it !=
mylist.end() ; ++it) {
cout << **it;
std::list<int>::const_iterator aux = it;
if(++aux != mylist.end())
cout << str;
}
>
Is there any better way? Comments on this? Anyway to do this more
straightforwardly?
>
Regards,
>
Paulo Matos
With an operator<< overload...

#include <iostream>
#include <ostream>
#include <list>
#include <algorithm>
#include <iterator>

template< typename T >
class NSequence
{
T t;
public:
NSequence(const T& r_t) : t(r_t) { }
T operator() () { return t++; }
};

template< typename T >
std::ostream&
operator<<(std::ostream& os, std::list< T >& r_l)
{
std::copy( r_l.begin(),
--r_l.end(),
std::ostream_iterator< int >(os, " + "));
return os << *(--r_l.end());
}

int main()
{
std::list< int nlist;
// insert integers from 1 to 6
std::generate_n( std::back_inserter(nlist),
6,
NSequence< int >(1) );
// print ints with " + "
std::cout << nlist << std::endl;
}

/*
1 + 2 + 3 + 4 + 5 + 6
*/

If you need the same with a std::list< int* >,
i'ld suggest wrapping it in a templated class with a std::list member.

  #6  
Old December 7th, 2006, 12:55 PM
Pete Becker
Guest
 
Posts: n/a

re: Using copy for output


Paulo Matos wrote:
Quote:
Pete Becker escreveu:
>
Quote:
>Paulo Matos wrote:
Quote:
>>If I have a list with 1,2,3,4,5 and I want to print " + " I would get 1
>>+ 2 + 3 + 4 + 5.
>std::copy(mylist.begin(), mylist.end(),
>std::ostream_iterator<int>(cout, " + ");
>>
>
That's what's I did iintially with '\n' however, it's not the same
thing. The result of that is:
1 + 2 + 3 + 4 + 5 +
>
Whoops, sorry. As long as you've got a bidirectional iterator, you can
do this:

mylist::iterator end = mylist.end();
if (mylist.begin() != end)
{
--end;
std::copy(mylist.begin(), end,
std::ostream_iterator<int>(cout, " + "));
std::copy(--mylist.end(), end,
std::ostream_iterator<int>(cout, ""));
}

Alternatively, you can write an algorithm that takes an output stream
rather than an iterator:

template <class InIt>
void show(InIt first, ostream& str, const char *sep)
{
if (first != last)
str << *first++;
while (first != last)
str << sep << *first++;
}

--

-- Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com)
Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." (www.petebecker.com/tr1book)
  #7  
Old December 7th, 2006, 01:05 PM
Pete Becker
Guest
 
Posts: n/a

re: Using copy for output


Salt_Peter wrote:
Quote:
return os << *(--r_l.end());
A note of caution here: this works if operator-- is a member of the
iterator type returned by end(), but doesn't work if it's a free
function. The problem is that -- modifies its argument. The call to
end() creates a temporary object, and you can't pass that to a
non-member function that takes its argument by reference.

--

-- Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com)
Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." (www.petebecker.com/tr1book)
  #8  
Old December 7th, 2006, 01:55 PM
Salt_Peter
Guest
 
Posts: n/a

re: Using copy for output



Pete Becker wrote:
Quote:
Salt_Peter wrote:
Quote:
return os << *(--r_l.end());
>
A note of caution here: this works if operator-- is a member of the
iterator type returned by end(), but doesn't work if it's a free
function. The problem is that -- modifies its argument. The call to
end() creates a temporary object, and you can't pass that to a
non-member function that takes its argument by reference.
>
Its a std::list so thats a bidirectional iterator with --iter and
iter-- member-operators available.
If the iterator involved was only a forward iterator, that would indeed
fail.

The warning about the temporary is relevant and for the record, i don't
like the above statement at all even if the reference to std::list<>
had been made const.

Thanks for your input.

  #9  
Old December 7th, 2006, 02:15 PM
Pete Becker
Guest
 
Posts: n/a

re: Using copy for output


Salt_Peter wrote:
Quote:
Pete Becker wrote:
Quote:
>Salt_Peter wrote:
Quote:
>> return os << *(--r_l.end());
>A note of caution here: this works if operator-- is a member of the
>iterator type returned by end(), but doesn't work if it's a free
>function. The problem is that -- modifies its argument. The call to
>end() creates a temporary object, and you can't pass that to a
>non-member function that takes its argument by reference.
>>
>
Its a std::list so thats a bidirectional iterator with --iter and
iter-- member-operators available.
It's a std::list, so it provides a bidirectional iterator. The
requirement for bidirectional iterators is that the expressions --iter
and iter-- are both valid and have specified semantics. They are not
required to be implemented with member functions. If pre-increment is a
free function, --r_l.end() is ill-formed.

--

-- Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com)
Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." (www.petebecker.com/tr1book)
  #10  
Old December 7th, 2006, 03:35 PM
Paulo Matos
Guest
 
Posts: n/a

re: Using copy for output




Thanks a lot for all your input. :) Great, I just learned some more C++
today!

Closed Thread


Similar Threads
Thread Thread Starter Forum Replies Last Post
Unary functor on algorithm using copy constructor Dijkstra answers 11 July 10th, 2008 05:55 PM
problems using copy() and rename() mantrid answers 12 October 22nd, 2006 02:25 PM
Using Copy (Ctrl-C) functionality with disabled JTextFields JMBollard answers 3 July 17th, 2005 11:20 PM