我正在尝试打印STL容器。我想要的是打印用分隔符分隔的容器的elemets。 但是我遇到了一些问题。
1。 g ++ vs 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完成所有这些。不编译其中任何一个。
有人可以帮我澄清这件事吗?谢谢。
答案 0 :(得分:5)
<强>的前提:强>
首先,代码是非法的,因为它错过了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
}
这会为您的程序注入未定义的行为。根据C ++ 11标准的第6.6.3 / 1段,事实上:
[...]离开函数末尾相当于没有值的返回; 这导致未定义 价值回归函数中的行为。
关于您的第一个问题:
修复后,您的代码就可以了,VC9附带的标准库的实现可能存在错误。
实际上,编译器应该在参数(operator <<
)的命名空间和调用的命名空间(全局命名空间)中查找符合条件的std
重载。只要您的运算符在全局命名空间和中定义,语句cout << s_v
就在全局命名空间中,重载解析应该成功地选择您的重载。
关于您的第二个问题:
为什么呢?模板未使用。它有关系吗?
这很简单:编译器无法从函数参数中推导出T
,因此除非您明确指定它,否则会导致编译错误。但是,明确指定模板参数意味着执行类似下面的操作,这几乎是无意义的:
::operator << <void>(std::cout, s_v);
在C ++ 11中,您可以为T
指定一个默认参数,这会使函数调用合法,然后再次出错,出于什么目的?
关于您的第三个问题:
当在推导的上下文中至少有一个函数参数的类型中使用T
时,编译器将允许从函数参数中推导出它(在这种情况下,它将推导出{{1} ,并且您不必明确指定它。
<强>结论:强>
总而言之:在添加必要的T = std::string
语句后,您的程序的第一个和第三个版本是合法的并且有意义,而第二个版本则不是,而不是。
答案 1 :(得分:1)
发布后,您的代码不应该使用任何编译器进行编译。
你缺少包括,以及很多std::
。我怀疑的内容
正在发生的是,你没有所有必要的
包括;特别是,#include <string>
缺失,
并且g ++间接地接受它。这很好奇。该
问题通常是相反的:VC ++吸收了很多
额外包括。然而,有时只是部分(所以你可能会
最终了解std::string
,但不了解非会员
与其相关的函数,如operator<<
)。没有
然而,看到你的实际包含,很难说。
编译器只能执行重载决策
功能,而不是功能模板。在开始过载之前
解决方案,它试图用实例化实例化功能模板
正确的名字。成功的实例化导致
一个函数,它添加到重载集。但是怎么回事
应该实例化你的功能模板。它没有办法
了解T
的用途。所以它没有实例化
(模板参数推导失败),并且没有找到它的实例
它进入过载集的方式。
我在这里看不到任何东西。添加后
在operator<<
中缺少返回,它编译并运行
正确地在VC ++上。