为什么不能用T = vector< int>实例化运算符<<(ostream& amp; vector< T& [英] Why can't I instantiate operator<<(ostream&, vector<T>&) with T=vector<int>?

查看:128
本文介绍了为什么不能用T = vector< int>实例化运算符<<(ostream& amp; vector< T&的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在思考 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<< \\\
; // this line works
std :: cout<< vv< \\\
; //这行产生错误
}

我用gcc编译这个程序, 100行错误。我相信有关部分是:


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



/ usr / include / c ++ / 4.4 / bits / stream_iterator.h:191:错误:没有匹配'operator<<'in'*((std :: ostream_iterator>,char,std :: char_traits > *)this) - > std :: ostream_iterator>,char,std :: char_traits> :: _ M_stream<< __value'


为什么会失败?在我的模板运算符<< 中,我尝试指定任何向量那么为什么 std :: vector< std :: vector<> print?



strong> EDIT :在模板函数中使用以下代码使其工作

  #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


解决方案

两个字:名称查找。



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

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

命名空间ns {
class C {};

void f(int){}

void test(){f(C()); } //不起作用:'(
}

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

在此示例中,在 main(),在正常名称查找期间找到的唯一 f 是全局命名空间中的函数模板,并且它匹配,因此 main 使用它( ns :: f 也在参数相关的查找中找到,但它不是一个匹配,所以全局 c ns :: f(int)找到重载并停止名称查找向外搜索命名空间,因此搜索 ns 首先,然后是全局命名空间,但是名称查找停止,一旦找到名称,因此一旦找到 ns :: f(int),名称查找停止。也发生,并且还发现 ns :: f(int),因为 C 在命名空间 ns ,则ADL将停止搜索。



在您的示例中也是如此: main code>,找到运算符<< 重载,但在 std :: ostream_iterator 它位于 std 命名空间中,找到其他<< 重载,因此找不到重载。



您的运算符<< 重载需要位于 std 命名空间,但不幸的是,您不能向 std 命名空间添加名称。


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 << "\n"; // this line works
    std::cout << vv << "\n"; // 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

解决方案

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.

这篇关于为什么不能用T = vector&lt; int&gt;实例化运算符&lt;&lt;(ostream&amp; amp; vector&lt; T&的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆