Is it possible to pass a map container to the copy algorithm and display it to the std::cout? If so how?

What I tried below doesn't work but it looks like it should. Any comments or pointers will be appreciated.

#include <iostream>
#include <string>
#include <map>
#include <algorithm>
#include <iterator>

std::ostream& operator<<(std::ostream & out, const std::pair<std::string, unsigned long> & p)
{
  return out << p.first << " " << p.second;
}

int main(int argc, char**argv)
{
  std::map<std::string, unsigned long> the_words;
  
  for (int i = 1; i < argc; ++i)
    ++the_words[argv[i]];
  
  std::map<std::string, unsigned long>::const_iterator begin = the_words.begin();
  
  std::cout << *begin << std::endl;
  
  //copy(the_words.begin(), the_words.end(), std::ostream_iterator< std::pair<std::string, unsigned long> >(std::cout, "\n"));
  return 0;
}

Recommended Answers

All 17 Replies

I would think that if you replace the type std::pair<std::string, unsigned long> in lines 7 and 23 by std::pair<const std::string, unsigned long>, it ought to work. At least I can't think immediately of any reason it shouldn't.

It looks like the problem could be with ostream_iterator, though I'm not familiar with the copy algorithm, it seems like something I'd use a void function pointer for, or boost lambda if I was being lazy.

Would you mind posting the errors the call to copy generates (if any)? Yes I know, it'll be a terrible cloud of template-type errors that runs on infinitely down your compiler output, I hate those too... but they are a necessary evil :(

If there are no errors, please give an example of output.

I tried your suggestions and the code fails to compile..Here's the update code

#include <iostream>
#include <string>
#include <map>
#include <algorithm>
#include <iterator>

std::ostream& operator<<(std::ostream & out, const std::pair<const std::string, unsigned long> & p)
{
  return out << p.first << " " << p.second;
}

int main(int argc, char**argv)
{
  std::map<std::string, unsigned long> the_words;
  
  for (int i = 1; i < argc; ++i)
    ++the_words[argv[i]];
  
  std::map<std::string, unsigned long>::const_iterator begin = the_words.begin();
  
  std::cout << *begin << std::endl;
  
  copy(the_words.begin(), the_words.end(), std::ostream_iterator< std::pair<const std::string, unsigned long> >(std::cout, "\n"));
  return 0;
}

Here's the compiler errors...The whole lot

g++ testit.cpp -Wall -ansi -pedantic -o testit
In file included from /usr/include/c++/4.4/iterator:67,
from testit.cpp:5:
/usr/include/c++/4.4/bits/stream_iterator.h: In member function ‘std::ostream_iterator<_Tp, _CharT, _Traits>& std::ostream_iterator<_Tp, _CharT, _Traits>::operator=(const _Tp&) [with _Tp = std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, long unsigned int>, _CharT = char, _Traits = std::char_traits<char>]’:
/usr/include/c++/4.4/bits/stl_algobase.h:313: instantiated from ‘static _OI std::__copy_move<<anonymous>, <anonymous>, <template-parameter-1-3> >::__copy_m(_II, _II, _OI) [with _II = std::_Rb_tree_iterator<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, long unsigned int> >, _OI = std::ostream_iterator<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, long unsigned int>, char, std::char_traits<char> >, bool <anonymous> = false, bool <anonymous> = false, <template-parameter-1-3> = std::bidirectional_iterator_tag]’
/usr/include/c++/4.4/bits/stl_algobase.h:397: instantiated from ‘_OI std::__copy_move_a(_II, _II, _OI) [with bool _IsMove = false, _II = std::_Rb_tree_iterator<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, long unsigned int> >, _OI = std::ostream_iterator<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, long unsigned int>, char, std::char_traits<char> >]’
/usr/include/c++/4.4/bits/stl_algobase.h:436: instantiated from ‘_OI std::__copy_move_a2(_II, _II, _OI) [with bool _IsMove = false, _II = std::_Rb_tree_iterator<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, long unsigned int> >, _OI = std::ostream_iterator<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, long unsigned int>, char, std::char_traits<char> >]’
/usr/include/c++/4.4/bits/stl_algobase.h:468: instantiated from ‘_OI std::copy(_II, _II, _OI) [with _II = std::_Rb_tree_iterator<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, long unsigned int> >, _OI = std::ostream_iterator<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, long unsigned int>, char, std::char_traits<char> >]’
testit.cpp:23: instantiated from here
/usr/include/c++/4.4/bits/stream_iterator.h:191: error: no match for ‘operator<<’ in ‘*((std::ostream_iterator<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, long unsigned int>, char, std::char_traits<char> >*)this)->std::ostream_iterator<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, long unsigned int>, char, std::char_traits<char> >::_M_stream << __value’
/usr/include/c++/4.4/ostream:108: note: candidates are: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>& (*)(std::basic_ostream<_CharT, _Traits>&)) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/include/c++/4.4/ostream:117: note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ios<_CharT, _Traits>& (*)(std::basic_ios<_CharT, _Traits>&)) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/include/c++/4.4/ostream:127: note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::ios_base& (*)(std::ios_base&)) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/include/c++/4.4/ostream:165: note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/include/c++/4.4/ostream:169: note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long unsigned int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/include/c++/4.4/ostream:173: note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(bool) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/include/c++/4.4/bits/ostream.tcc:91: note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(short int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/include/c++/4.4/ostream:180: note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(short unsigned int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/include/c++/4.4/bits/ostream.tcc:105: note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/include/c++/4.4/ostream:191: note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(unsigned int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/include/c++/4.4/ostream:200: note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long long int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/include/c++/4.4/ostream:204: note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long long unsigned int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/include/c++/4.4/ostream:209: note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(double) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/include/c++/4.4/ostream:213: note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(float) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/include/c++/4.4/ostream:221: note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long double) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/include/c++/4.4/ostream:225: note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(const void*) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/include/c++/4.4/bits/ostream.tcc:119: note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_streambuf<_CharT, _Traits>*) [with _CharT = char, _Traits = std::char_traits<char>]

& std::ostream_iterator<_Tp, _CharT, _Traits>::operator=(const _Tp&) [with _Tp = std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, long unsigned int>

and that messy looking std::pair is actually how <string, long> is represented in the template hierarchy.

std::ostream_iterator = std::pair<std::string, unsigned long>; <--- is your issue imo

& std::ostream_iterator<_Tp, _CharT, _Traits>::operator=(const _Tp&) [with _Tp = std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, long unsigned int>

and that messy looking std::pair is actually how <string, long> is represented in the template hierarchy.

std::ostream_iterator = std::pair<std::string, unsigned long>; <--- is your issue imo

So is this an issue with gnu g++ compiler?

I don't think that it is a compiler specific issue.
It may be an issue with the construction of ostream_iterator you pass the copy function.
I understand you are using this to write to the beginning of the std::cout file buffer, but I am unfamiliar with the copy semantics.

At minimum, ostream_iterator has an issue with the operators << and =, it is not resolving the type you are passing to the function. I don't think the std::string must be const type.

I think that you will need to overload std::ostream operator=, as the std::pair is not a primitive or normal output type, and it may find the shallow copying of the complex class to be insufficient. I do not believe that ostream handles std::pair's assignment by default, though of course I may be mistaken.

arkoenig wrote:
> I would think that if you replace the type std::pair<std::string, unsigned long> in
> lines 7 and 23 by std::pair<const std::string, unsigned long>, it ought to work.
> At least I can't think immediately of any reason it shouldn't.

I had always thought that this error (given by every compiler that I've used, even with std::pair<const std::string, unsigned long>) is because of Koenig lookup. Though I've never really understood why SFINAE does not apply in this case.

But if Koenig himself says that that it ought to work, my understanding is obviously incorrect. So what's going on here?

Before I close this, can anyone tell me if this will compile on different compiler. I know it fails on GCC's g++ but I'm curious to see if it'll succeed on a different one.

I was curious so I trolled google a little bit, and chanced upon a solution to your problem:

namespace
{
std::string toString( const std::pair< size_t, size_t >& data)
{
    std::ostringstream str;
    str << data.first << ", " << data.second;
    return str.str();
}
} // namespace anonymous

std::transform( 
    some_map.begin(), 
    some_map.end(), 
    std::ostream_iterator< std::string >( std::cout, "\n" ),
    toString );
commented: Thanks for trolling around +4

I was curious so I trolled google a little bit, and chanced upon a solution to your problem:

namespace
{
std::string toString( const std::pair< size_t, size_t >& data)
{
    std::ostringstream str;
    str << data.first << ", " << data.second;
    return str.str();
}
} // namespace anonymous

std::transform( 
    some_map.begin(), 
    some_map.end(), 
    std::ostream_iterator< std::string >( std::cout, "\n" ),
    toString );

Just tried your solution and it works...Thanks everyone.

#include <iostream>
#include <string>
#include <map>
#include <iterator>
#include <sstream>
#include <algorithm>

namespace
{
  std::string toString( const std::pair< std::string, unsigned long >& data)
  {
      std::ostringstream str;
      str << data.first << ", " << data.second;
      return str.str();
  }
}

int main(int argc, char**argv)
{
  std::map<std::string, unsigned long> the_words;
 
  for (int i = 1; i < argc; ++i)
    ++the_words[argv[i]];

  std::transform( the_words.begin(), the_words.end(), std::ostream_iterator< std::string >( std::cout, "\n" ),toString );
 
  return 0;
}

usage/output

./testit this is the test
is, 1
test, 1
the, 1
this, 1

Edit: this was for the first page ;p

Doesn't compile on VC++ 2010

Edit: this was for the first page ;p

Doesn't compile on VC++ 2010

So it wasn't GCC's g++ compiler or standard libraries. That's good to know, thank-you for posting/verifying.

arkoenig wrote:
> I would think that if you replace the type std::pair<std::string, unsigned long> in
> lines 7 and 23 by std::pair<const std::string, unsigned long>, it ought to work.
> At least I can't think immediately of any reason it shouldn't.

I had always thought that this error (given by every compiler that I've used, even with std::pair<const std::string, unsigned long>) is because of Koenig lookup. Though I've never really understood why SFINAE does not apply in this case.

But if Koenig himself says that that it ought to work, my understanding is obviously incorrect. So what's going on here?

I didn't say it ought to work -- I said that I didn't immediately see a reason that it shouldn't. As it happens, I made that post before I had had my morning coffee :-)

I didn't say it ought to work -- I said that I didn't immediately see a reason that it shouldn't. As it happens, I made that post before I had had my morning coffee :-)

regardless, you were correct, a pair object contained in a map container has its first member defined as constant.

I didn't say it ought to work -- I said that I didn't immediately see a reason that it shouldn't. As it happens, I made that post before I had had my morning coffee :-)

Phew! Thank you. You had me worried for a while.

I actually found the answer here at Daniweb...It turns out that the C++ standard won't allow the std::pair and copy to work together if the elements of std::pair are both or one each of built in types or std::types.

http://www.daniweb.com/software-development/cpp/threads/154030

So after many months on the back burner, Daniweb comes to the rescue.

#include <iostream>
#include <string>
#include <map>
#include <algorithm>
#include <iterator>

struct mys
{
    unsigned long x;
};

std::ostream& operator <<(std::ostream & out, const std::pair<const std::string, struct mys> & p)
{
    return out << p.first << " " << p.second.x;
}

int main(int argc, char** argv)
{
    std::map<std::string, struct mys> the_words;

    the_words["G4143"].x += 1;
    the_words["G4143"].x += 1;
    the_words["was"].x += 1;
    the_words["here"].x += 1;
    
    copy(the_words.begin(), the_words.end(), std::ostream_iterator< const std::pair<const std::string, struct mys> >(std::cout, " "));

    std::endl(std::cout);
    
    return 0;
}
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.