Search code examples
c++templatesstliteratorostream

ostream_iterator operator= fails on pair<int,int>, but works on wrapper class. Can't I overload operator<< for pair<>?


I'm trying to use stl idioms to print the content of a vector of pairs, by defining the operator<< for the pair, and it fails, unless I use a wrapper class:

typedef pair<int, int> P;
// Dump wrapper, just converting implicitly pair<int, int> to PC.
class PC { public: int first; int second; PC(const P& p) { first = p.first; second = p.second;}};

ostream& operator<<(ostream& o, const PC& v) {
    return o << "(" << v.first << "," << v.second << ")";
}

ostream& operator<<(ostream& o, const P& v) {
    return o << "(" << v.first << "," << v.second << ")";
}

int main(int argc, const char * argv[]) {
    P p = {10,20};
    cout << p; // works
    *ostream_iterator<PC>(cout, ", ") = p; // works
    *ostream_iterator<P>(cout, ", ") = p; // fails, error msg below
}

iterator:974:28: Invalid operands to binary expression ('std::__1::ostream_iterator, char, std::__1::char_traits >::ostream_type' (aka 'basic_ostream >') and 'const std::__1::pair')

_LIBCPP_INLINE_VISIBILITY ostream_iterator& operator=(const _Tp& __value_)
    {
        *__out_stream_ << __value_; //// <<<---- Here is the error line
        if (__delim_)
            *__out_stream_ << __delim_;
        return *this;
    }

It seems the my operator<<(ostream&o, const P&) isn't being found. Is that because it is in the global namespace instead of being in std namespace?


Solution

  • The std::pair<int,int> is not type from global namespace unlike PC and so your operator<< overload does not participate in overload resolution. It will likely work if you define it in namespace std:

    namespace std {
        ostream& operator<<(ostream& o, const P& v) {
            return o << "(" << v.first << "," << v.second << ")";
        }  
    }
    

    However that is incorrect to do since the pair<int,int> does not depend on any user defined types. Your usage of wrappers is better idea.