Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
161 views
in Technique[技术] by (71.8m points)

c++ - Why can't I instantiate operator<<(ostream&, vector<T>&) with T=vector<int>?

In thinking about C++ iterator question, I wrote this sample program:

#include <vector>
#include <iostream>
#include <iterator>
#include <algorithm> 

template <class T>
std::ostream& operator<<(std::ostream&os, const std::vector<T>& v) 
{ 
    os<<"(";
    std::copy(v.begin(), v.end(), std::ostream_iterator<T>(os, ", "));
    return os<<")";
}

int main()
{
    std::vector<int> v(3);
    std::vector<std::vector<int> > vv(3, v);
    std::cout << v << "
"; // this line works
    std::cout << vv << "
"; // this line produces error
}

I compile this program with gcc and get the typical 100 lines of errors. The relevant part, I believe, is:

it.cc:19: instantiated from here

/usr/include/c++/4.4/bits/stream_iterator.h:191: error: no match for ‘operator<<’ in ‘((std::ostream_iterator >, char, std::char_traits >)this)->std::ostream_iterator >, char, std::char_traits >::_M_stream << __value’

Why does this fail? In my templated operator<<, I try to specify that any vector, regardless of type, is printable. So why doesn't std::vector<std::vector<>> print?

EDIT: Using the following code in the template function makes it work

#if 0
    std::copy(v.begin(), v.end(), std::ostream_iterator<T>(os, ", "));
#else
    for(typename std::vector<T>::const_iterator it = v.begin();
        it != v.end();
        it++) {
        os<<(*it)<<", ";
    }
#endif
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Two words: name lookup.

Here is a simplified example of what you are trying to do, without any Standard Library headers required:

template <typename T> void f(T) { }

namespace ns {
    class C { };

    void f(int) { }

    void test() { f(C()); } // doesn't work :'(
}

int main() {
    f(ns::C());             // works!  :-D
}

In this example, in main(), the only f that is found during normal name lookup is the function template in the global namespace, and it matches, so main uses it (ns::f is also found during argument-dependent lookup, but it isn't a match so the global f is still selected during overload resolution).

In test, however, the ns::f(int) overload is found and name lookup stops. Namespaces are searched outwards, so ns is searched first, then the global namespace, but name lookup stops once a name is found, so once ns::f(int) is found, name lookup stops. Argument-dependent lookup also takes place and also finds ns::f(int), since C is in namespace ns, then ADL stops searching.

The same is true in your example: in main(), the operator<< overload is found, but inside of the std::ostream_iterator, which is in the std namespace, other << overloads are found, and so your overload is not found.

Your operator<< overload would need to be in the std namespace for it to work, but unfortunately you aren't allowed to add names to the std namespace.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

56.9k users

...