我正在尝试漂亮地打印一个 STL 容器。我想做的是打印一个用定界符分隔的容器的元素。 但是我遇到了一些问题。
<强>1。 g++ 与 VC++
ostream& operator<<(ostream& o, const vector<string>& v) {
copy(v.begin(), v.end(), std::ostream_iterator<string>(o,","));
}
int main()
{
vector<string> s_v;
s_v.push_back("one");
s_v.push_back("two");
cout << s_v;
}
g++(mingw32 上的 gcc 版本 4.4.0)可以编译它并且工作正常。 VC++ (Visual Studio 9) 无法编译此代码。
error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'const std::string' (or there is no acceptable conversion)
1> c:\program files (x86)\microsoft visual studio 9.0\vc\include\ostream(653): could be 'std::basic_ostream<_Elem,_Traits> &std::operator <<<char,std::char_traits<char>>(std::basic_ostream<_Elem,_Traits> &,const char *)'
1> with
1> [
这是为什么?这个代码是非法的吗?或者它只是 VC++ beign VC++?
<强>2。未使用的模板变量中断编译。
如果现在我像这样向 ostream 添加一个模板(它没有被使用,只是坐在那里)
template <typename T> // <----- Here
ostream& operator<<(ostream& o, const vector<string>& v) {
copy(v.begin(), v.end(), std::ostream_iterator<string>(o,","));
}
int main()
{
vector<string> s_v;
s_v.push_back("one");
s_v.push_back("two");
cout << s_v;
}
gcc 无法匹配操作符了。
error: no match for 'operator<<' in 'std::cout << s_v'
and a lot more candidates...
为什么?该模板未使用。这有关系吗?
编辑:这已解决。我不得不返回 o;
<强>3。使用的模板
template <typename T>
ostream& operator<<(ostream& o, const vector<T>& v) {
copy(v.begin(), v.end(), std::ostream_iterator<T>(o,","));
return o; // Edited
}
int main()
{
vector<string> s_v;
s_v.push_back("one");
s_v.push_back("two");
vector<int> i_v;
i_v.push_back(1);
i_v.push_back(2);
cout << s_v;
cout << i_v;
}
如果我知道使用模板类型。 g++ 可以编译它,但随后会因异常而终止。
terminate called after throwing an instance of 'std::bad_cast'
what(): std::bad_cast
VC++ 只是坐着看着 gcc 做这一切。不编译它们中的任何一个。
有人可以为我澄清一下吗?谢谢。
最佳答案
前提:
首先,该代码是非法的,因为它缺少一个return
。声明(这可能是导致第三个版本中引发异常的原因):
ostream& operator<<(ostream& o, const vector<string>& v) {
copy(v.begin(), v.end(), std::ostream_iterator<string>(o,","));
return o; // <== THIS ONE WAS MISSING
}
这会向您的程序注入(inject)未定义的行为。根据 C++11 标准的第 6.6.3/1 段,事实上:
[...] Flowing off the end of a function is equivalent to a return with no value; this results in undefined behavior in a value-returning function.
关于您的第一个问题:
一旦修复,您的代码就可以了,VC9 附带的标准库的实现可能有错误。
事实上,编译器应该查找符合条件的 operator <<
重载。在参数的命名空间( std
)和进行调用的命名空间(全局命名空间)中。只要你的运算符定义在全局命名空间和语句cout << s_v
在全局命名空间中,重载解析应该成功地选择你的重载。
关于你的第二个问题:
Why? the template is unused. Should it matter?
这很简单:编译器无法推导出T
。来自函数参数,因此除非您明确指定它,否则这将导致编译错误。但是,显式指定模板参数将意味着执行类似以下的操作,这几乎是无意义的:
::operator << <void>(std::cout, s_v);
在 C++11 中,您可以为 T
指定默认参数,这将使函数调用合法,然后再次出现错误,目的是什么?
关于第三个问题:
当 T
用于推导上下文中至少一个函数参数的类型,编译器将允许从函数参数推导它(在这种情况下,它将推导 T = std::string
,并且您不必指定它明确地。
结论:
总结一下:在添加必要的 return
之后声明,你的程序的第一个和第三个版本是合法的和有意义的,而第二个不是也没有。
关于c++ - 模板重载 ostream 运算符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15770613/