2
#include <string>
#include <iostream>
#include <map>
#include <utility>
using namespace std;


int main()
{

   map<int, string> Employees;

   // 1) Assignment using array index notation
   Employees[5234] = "Mike C.";
   Employees[3374] = "Charlie M.";
   Employees[1923] = "David D.";
   Employees[7582] = "John A.";
   Employees[5328] = "Peter Q.";

   cout << Employees;

   cout << "Employees[3374]=" << Employees[3374] << endl << endl;

   cout << "Map size: " << Employees.size() << endl;

   /*for( map<int,string>::iterator ii=Employees.begin(); ii!=Employees.end(); ++ii)
   {
       cout << (*ii).first << ": " << (*ii).second << endl;
   }*/
   system("pause");
}

I would like to know what to add in order for me to print cout << Employees; instead of using iterator.Because I did see some code can directly print the map content with just the simple cout << Anythg.I wonder what has made the code work?

Jaden Ng
  • 141
  • 1
  • 12
  • 1
    If you overload operator << for map you probably could. – Borgleader Sep 04 '13 at 02:21
  • But you're not allowed to add that overload to `std::map` IIRC. – chris Sep 04 '13 at 02:22
  • 1
    Do you mean this? http://stackoverflow.com/questions/10750057/c-printing-out-the-contents-of-a-vector Look at second answer. – Neil Kirk Sep 04 '13 at 02:23
  • @Borgleader, Here, I had a [chat conversation](http://chat.stackoverflow.com/transcript/message/10469991#10469991). – chris Sep 04 '13 at 02:24
  • @NeilKirk: That won't work for a map, as the `value_type` is `std::pair` and there is no `operator<<` defined for `std::pair`. To be able to use the `ostream_iterator` you would need to provide an implementation of `operator<<` for the pair type, which is not legal in this case. – David Rodríguez - dribeas Sep 04 '13 at 02:26
  • @Borgleader: There are two reasons, the first of which is that in this particular case none of the types is user defined. You can only overload operators when at least one of the types is user defined. Even if that were to be legal (using a wide definition of *user defined* that includes *library defined*, which could be an interpretation), you could not do it *right* as you are not allowed to add new overloads inside the `std` namespace and that means that the operator will not be found through ADL, and in most contexts that means that it would not be found at all. – David Rodríguez - dribeas Sep 04 '13 at 02:30
  • @DavidRodríguez-dribeas So help the guy that just arrived, David. That means I *can* override `operator <<(std::ostream&, const std::map&)`, but providing a *template* version for a generic map is a no-no? Did I understand that right? – WhozCraig Sep 04 '13 at 02:33
  • 1
    @DavidRodríguez-dribeas I know you can't add stuff to std, but your statement seem to imply that [this shouldn't work](http://coliru.stacked-crooked.com/a/a068abe775119983) – Borgleader Sep 04 '13 at 02:41
  • @Borgleader, Well, you typically have stuff in your own namespace and that definitely wouldn't be found through ADL (and we don't want to be going `foo::operator<<(std::cout, theMap);`). Anyway, it still conflicts with the first point, which should just be UB if you do it. – chris Sep 04 '13 at 02:45
  • @DavidRodriguez-dribeas Where is the "you can only override an operator if one of the types is user defined"? I'd consider that best practices, but wasn't aware it was UB. – Yakk - Adam Nevraumont Sep 04 '13 at 11:40
  • @Borgleader: I was misremembering, the requirement is wider than I thought and only limits operator overloading to classes, enums and class enums (I thought the wording was user-defined types). So it seems that it is legal, although the second part of the statement still is in effect: you cannot do it inside `::std`, so it cannot be found by ADL. In a toy example it works, once the call is from a different namespace that has a type for which `operator<<` is overloaded, the operator in the global namespace will not be found. *Make a tiny mistake and get 4 comments :)* – David Rodríguez - dribeas Sep 04 '13 at 12:52
  • @DavidRodríguez-dribeas Oh I see now, thanks for the clarification. Also welcome to SO ;) – Borgleader Sep 04 '13 at 14:00

1 Answers1

4

Nop, or at least the standard library doesn't provide a default implementation of operator << for container and std::ostream.

Check out https://github.com/louisdx/cxx-prettyprint or write your own implementation of operator<<(std::ostream &, const std::map<T1, T2> &).

Here is simple implemenation, for the sake of example:

#include <map>
#include <string>
#include <iostream>

template<typename T1, typename T2>
std::ostream &operator<<(std::ostream &stream, const std::map<T1, T2>& map)
{
  for (typename std::map<T1, T2>::const_iterator it = map.begin();
       it != map.end();
       ++it)
    {
      stream << (*it).first << " --> " << (*it).second << std::endl;
    }
  return stream;
}

int     main(int, char **)
{
  std::map<std::string, int> bla;

  bla["one"] =  1;
  bla["two"] = 2;
  std::cout << bla << std::endl;
  return (0);
}
Xaqq
  • 4,308
  • 2
  • 25
  • 38
  • I personally would avoid this design, as it involves overriding an operator for two classes, neither of which are "mine". If I needed this, I'd write a function `pretty_print` which would take a map, return a `please_pretty_print>` object with a reference to the `map`, and override `<<( ostream&, please_pretty_print>)`. But I'm strange. – Yakk - Adam Nevraumont Sep 04 '13 at 11:36
  • Also note that this operator won't be found in most programs. Say that the function instead of `main` was `ns::foo` and that there is a type `ns::T` for which an overloaded `ns::operator<<` is defined. Regular lookup will find `ns::operator<<`, and ADL will add only `::std` to the set, where this operator is not present. – David Rodríguez - dribeas Sep 04 '13 at 12:55
  • @DavidRodríguez-dribeas Moving the `operator<<` to the namespace `ns` would fix the problem. However, this doesn't feel like a good solution, because you would have to redefine the operator in every namespace that may use it. What could be done about that? – Xaqq Sep 04 '13 at 14:02
  • @Xaqq: When you say *move* do you really mean to *copy* it to each and every namespace in which you want to print the container? A single location won't do it, and this will result in code duplication, larger binary sizes... A named function as Yakk suggests is a much better approach – David Rodríguez - dribeas Sep 04 '13 at 14:48
  • @DavidRodríguez-dribeas Yeah by moving I meant copy. But as I said, it doesn't feel good. – Xaqq Sep 04 '13 at 17:07