10

I have declared an operator<< for std::pair<int, int>:

std::ostream& operator<<(std::ostream& o, const std::pair<int, int>& p) {
    o << p.first << p.second;
    return o;
}

I want to use this operator when i print my data:

std::vector<std::pair<int, int>> data;
std::copy(data.begin(), data.end(), std::ostream_iterator<std::pair<int, int>>(std::cout, "\n"));

But the compiler says, no match for operator<< ... What am i doing wrong?

TemplateRex
  • 69,038
  • 19
  • 164
  • 304
WonderCsabo
  • 11,947
  • 13
  • 63
  • 105
  • Note that if you have a type T in names pace N, to use the ostream_iterator + copy combination, your operator << for T needs to be in name space N not in ::. – mat_geek Sep 04 '14 at 08:15

4 Answers4

10

std::copy cannot find overloading for operator << for std::pair in std namespace. There is no good way, to overload operator << for object from std namespace in algorithms from std namespace.

You can use std::for_each with functor, that will print your values, for example with lambda.

std::for_each(data.begin(), data.end(), [](const std::pair<int, int>& p)
{
   std::cout << p << std::endl;
});

You cannot put overloading in std namespace, you can only add specializations for user-defined types since

The behavior of a C++ program is undefined if it adds declarations or definitions to namespace std or to a namespace within namespace std unless otherwise specified

A program may add a template specialization for any standard library template to namespace std only if the declaration depends on a user-defined type and the specialization meets the standard library requirements for the original template and is not explicitly prohibited.

ForEveR
  • 55,233
  • 2
  • 119
  • 133
3

Maybe you can try this:

struct PAIR : std::pair<int, int>
{
  using std::pair<int, int>::pair;
};

int main(int argc, char* argv[]) {
std::vector<std::pair<int, int>> data;
std::copy(data.begin(), data.end(), std::ostream_iterator<PAIR>(std::cout, "\n"));
    return 0;
}

Since there's already a good answer, I will simply quote the link:

The problem is that the name lookup does not find your operator<<(ostream& os, const PAIR& r). The code that tries to invoke the operator<< is in somewhere inside the ostream_iterator<> which is itself inside the std namespace. The name lookup looks around for the right function inside ostream_iterator<> and the std namespace; the argument dependent lookup does not help here because both of the parameters are in the std namespace, too.

So, my suggestion is (1) either to wrap your operator into namespace std { }, but that is UB, IIRC. Or (2) create a struct inheriting from std::pair to define a new type in your namespace, and using the ADL to find your operator<<().


Usage:

#include <iostream>
#include <limits>
#include <vector>
#include <iterator>
#include <map>

std::ostream& operator<<(std::ostream& o, const std::pair<int, int>& p) {
    o << p.first << p.second;
    return o;
}

struct PAIR : std::pair<int, int>
{
    using std::pair<int, int>::pair;
};

int main(int argc, char* argv[]) {
std::vector<std::pair<int, int> > data;
data.push_back(std::pair<int, int>(50, 42));
std::copy(data.begin(), data.end(), std::ostream_iterator<PAIR>(std::cout, "\n"));
    return 0;
}
Community
  • 1
  • 1
  • @Wonder Yeah you need C++11. The other option (as posted in the link) is a stream manipulator. –  Nov 29 '13 at 14:29
  • @Wonder Let me post the full code sample that compiled for me. –  Nov 29 '13 at 15:04
  • I just tried your complete code. I got `error: 'std::pair::pair' names constructor`. By the way i am using MINGW 4.7.2, maybe it does not supports this feature, yet. – WonderCsabo Nov 29 '13 at 17:15
  • @Wonder It works on both [ideone](http://ideone.com/gAP2UE) and [coliru](http://coliru.stacked-crooked.com/a/d641ff4b3ac3d07c) for me. Ah, I'm using 4.8.1. –  Nov 29 '13 at 17:16
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/42215/discussion-between-wondercsabo-and-remyabel) – WonderCsabo Nov 29 '13 at 17:17
1

The general case for those who's Google search brought you to the specific case...

Note that if you have a type T in names pace N, to use the ostream_iterator + copy combination, your operator << for T needs to be in name space N not in ::.

namespace N {
    class T;
    std::ostream & operator << ( std::ostream &; T const & );
}

In this case std::copy can find your define N::operator <<( std::ostream &; T const & )

You don't need to worry about qualifying access when you use the operator.

N::T t;
std::cout << t << std::endl;

and

std::list<N::t> alist;
alist.push_back(t);

std::ostream_iterator<N::t> out_itr(std::cout, "\n");
std::copy(alist.begin(), alist.end(), out_itr);
mat_geek
  • 2,481
  • 3
  • 24
  • 29
0
std::vector<std::pair<int, int> > data;
std::copy(data.begin(), data.end(), std::ostream_iterator<std::pair<int, int> >(std::cout, "\n"));

please try this, i think there has a space between >.

BlackMamba
  • 10,054
  • 7
  • 44
  • 67