为什么我不能用T = vector <int>实例化operator <<(ostream&,vector <T>&)?

Rob*_*obᵩ 13 c++ templates iostream

在考虑C++迭代器问题时,我编写了这个示例程序:

#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 << "\n"; // this line works
    std::cout << vv << "\n"; // this line produces error
}
Run Code Online (Sandbox Code Playgroud)

我用gcc编译这个程序,得到典型的100行错误.我相信相关部分是:

it.cc:19:从这里实例化

/usr/include/c++/4.4/bits/stream_iterator.h:191:错误:' ((std :: ostream_iterator>,char,std :: char_traits>)中的'operator <<'不匹配- > std :: ostream_iterator>,char,std :: char_traits> :: _ M_stream << __value'

为什么这会失败?在我的模板中operator<<,我尝试指定任何矢量,无论何种类型,都是可打印的.那为什么不std::vector<std::vector<>>打印?

编辑:在模板功能中使用以下代码使其工作

#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
Run Code Online (Sandbox Code Playgroud)

Jam*_*lis 16

两个词:名字查找.

以下是您尝试执行的操作的简化示例,不需要任何标准库标头:

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
}
Run Code Online (Sandbox Code Playgroud)

在此示例中main(),f在正常名称查找期间找到的唯一内容是全局命名空间中的函数模板,并且它匹配,因此main使用它(ns::f在参数依赖查找期间也可以找到它,但它不匹配所以f在重载决策期间仍然选择全局.

test,但是,ns::f(int)过载被发现,名称查找停止.命名空间向外搜索,因此ns首先搜索,然后搜索全局命名空间,但是一旦ns::f(int)找到名称就停止名称查找,因此一旦找到,名称查找就会停止.依赖于参数的查找也会发生,并且还会发现ns::f(int),因为C在命名空间中ns,ADL会停止搜索.

同样是在你的榜样真:在main()中,operator<<超载被发现,但里面的std::ostream_iterator,这是在std命名空间,其他的<<过载被发现,所以你的过载是找不到的.

您的operator<<重载需要在std命名空间中才能工作,但遗憾的是您不允许在std命名空间中添加名称.


Joh*_*itb 7

在函数模板的实例化上下文中查找仅使用ADL.没有不合格的查询.因此,您需要依赖ADL.但ADL查找vector<int>不包括全局命名空间,因此operator<<找不到.试试这个,这应该工作正常:

struct A { 
  operator int() const { return 0; }
};

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<A> v(3);
    std::vector< std::vector<A> > vv(3, v);
    std::cout << vv << "\n"; // should work fine
}
Run Code Online (Sandbox Code Playgroud)

这工作,因为全局命名空间与用于ADL查找集关联std::vector<A>(因为A是一个模板参数),为此实例的各个成员函数时找到全局声明的模板std::ostream_iterator<>,它会用你operator<<TA,这则反过来将使用operator<<(int)std::ostream.