rialmat
rialmat

Reputation: 133

Compile error when overloading operator<< with template arguments

I'm trying to use the stl copy () to print the key-value pair in a map. The code is as follows:

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

using namespace std;
//compile error if I comment out "namespace std"
namespace std {    
template<typename F, typename S> 
ostream& operator<<(ostream& os, const pair<F,S>& p) {
  return os << p.first << "\t" << p.second << endl;
}
}

int main() {
  map<int, int> m;
  fill_n(inserter(m, m.begin()), 10, make_pair(90,120));
  copy(m.begin(), m.end(), ostream_iterator<pair<int,int> >(cout,"\n"));
} 

I'm trying to overload operator<<. The problem is that the code won't compile unless I surround the definition of the overloaded operator<< with namespace std. I think it is due to the name lookup mechanism of C++, which I still have trouble understanding. Even if I define non-template version like this:

ostream& operator<<(ostream& os, const pair<int,int>& p) {
    return os << p.first << "\t" << p.second << endl;
}

It still won't compile. Can anyone explain why?

Upvotes: 3

Views: 175

Answers (1)

Jon Purdy
Jon Purdy

Reputation: 55059

Your problem is with argument-dependent name lookup (ADL). The compiler is searching for an implementation of operator<< in namespace std, as both ostream and pair are in that namespace. You should make a wrapper that forwards to operator<< from the correct namespace:

template<class T>
struct ostreamer {
  ostreamer(const T& value) : reference(value) {}
  const T& reference;
  friend ostream& operator<<(ostream& stream, const ostreamer& value) {
    return stream << value.reference;
  }
};

Then just use ostream_iterator<ostreamer<pair<const int, int>>> instead of ostream_iterator<pair<int, int>>. Note that because ostreamer stores by reference and not by value, you can’t rely on the implicit conversion from pair<const int, int> to pair<int, int> anymore. You could change ostreamer to store by value, but as it is, it has no overhead, and I think it’s better to be explicit anyway.

Upvotes: 2

Related Questions