Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ template operator not found as match

I'm trying to create a general operator<< for std::ostream and any Iterable type.

This is the code:

template <class T,template<class> class Iterable> inline std::ostream& operator<<(std::ostream& s,const Iterable<T>& iter){
    s << "[ ";
    bool first=false;
    for(T& e : iter){
        if(first){
            first=false;
            s << e;
        }else{
            s << ", " << e;
        }
    }
    s << " ]";
    return s;
}

Unfortunately my operator is not found as a match for a vector<uint> and the compiler tries to match with operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x) .

Any idea how I can change the overload to be recognized?

like image 818
tly Avatar asked Feb 07 '15 20:02

tly


1 Answers

The direct solution to your problem is that vector is a template on two types, not one, so you'd want to write:

template <typename... T, template <typename... > class Iterable>
inline std::ostream& operator<<(std::ostream& os, const Iterable<T...>& iter)
{
    s << "[ ";
    bool first = true; // not false
    for (const auto& e : iter) {
        // rest as before
    }
    return s << " ]";
}

That works, but is a little unsatisfying - since some things that are templates aren't iterable and some things that aren't templates are. Furthermore, we do not actually need either Iterable or T in our solution. So how about we write something that takes any Range - where we define Range as something that has a begin() and end():

template <typename Range>
auto operator<<(std::ostream& s, const Range& range) 
-> decltype(void(range.begin()), void(range.end()), s)
{
    // as above, except our container is now named 'range'
}

If that's too general, then you can do:

template <typename T> struct is_range : std::false_type;
template <typename T, typename A>
struct is_range<std::vector<T,A>> : std::true_type;
// etc.

template <typename Range>
typename std::enable_if<
    is_range<Range>::value,
    std::ostream&
>::type
operator<<(std::ostream& s, const Range& range)    
like image 109
Barry Avatar answered Nov 02 '22 17:11

Barry