1

I have a set of pairs of integers and I want to print it, so I overloaded << operator for set and pair classes as :

template<typename T, typename U>
inline ostream& operator<<(ostream& os, pair<T,U> &p){
    os<<"("<<p.first<<","<<p.second<<")";
    return os;
}


template<typename T>
inline ostream& operator<<(ostream& os, set<T> &s){
    os<<"{";
    for(auto it = s.begin() ; it != s.end() ; it++){
        if(it != s.begin())
            os<<",";
        os<<*it;
    }
    os<<"}";
    return os;
}

When I create a set and output it like

set<pair<int,int>> s;
cout<<s<<endl;

It gives the errors :

cannot bind ‘std::ostream {aka std::basic_ostream<char>}’ lvalue to ‘std::basic_ostream<char>&&’
   os<<*it;

and

initializing argument 1 of ‘std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char; _Traits = std::char_traits<char>; _Tp = std::pair<int, int>]’
     operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x)

I don't know what is the problem, the errors are very cryptic. Moreover, if I create a set of integers and print it, it works fine.

2 Answers 2

5

The type of it in auto it = s.begin() is a const_iterator(source). as such when you call os<<*it; you need a function that can take a const pair. If you change you code to this it will work:

#include <iostream>
#include <set>
#include <utility>

using namespace std;

template<typename T, typename U>
inline ostream& operator<<(ostream& os, const pair<T,U> &p){
    os<<"("<<p.first<<","<<p.second<<")";
    return os;
}


template<typename T>
inline ostream& operator<<(ostream& os, const set<T> &s){
    os<<"{";
    for(auto it = s.begin() ; it != s.end() ; it++){
        if(it != s.begin())
            os<<",";
        os<<*it;
    }
    os<<"}";
    return os;
}

int main()
{
    set<pair<int,int>> s {{1,2}};
    cout<<s<<endl;
}

Live Example

I would also suggest that you always take the second parameter as a const & for

  1. You can bind a temporary to a const & (ex function returns)

  2. You should not be modifying the container during output so this uses the C++ type system to enforce that.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, actually, when I wrote this for vector (instead of set), it worked, that's why I got confused.
2

The stream operators are not meant to modify the value their are passed. Hence, you should accept a const reference instead of a mutable reference:

template<typename T, typename U>
inline ostream& operator<<(ostream& os, const pair<T,U> &p){
    os<<"("<<p.first<<","<<p.second<<")";
    return os;
}


template<typename T>
inline ostream& operator<<(ostream& os, const set<T> &s){
    os<<"{";
    for(auto it = s.begin() ; it != s.end() ; it++){
        if(it != s.begin())
            os<<",";
        os<<*it;
    }
    os<<"}";
    return os;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.