为什么不能用T = vector< int>实例化运算符<<(ostream& amp; vector< T& [英] Why can't I instantiate operator<<(ostream&, vector<T>&) with T=vector<int>?
问题描述
在思考 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< int>实例化运算符<<(ostream& amp; vector< T&的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!