5 c++ templates operator-overloading
我想打印一个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;
}
Run Code Online (Sandbox Code Playgroud)
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> [
Run Code Online (Sandbox Code Playgroud)
为什么是这样?这段代码是非法的吗?或者它只是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;
}
Run Code Online (Sandbox Code Playgroud)
gcc不再匹配运营商.
error: no match for 'operator<<' in 'std::cout << s_v'
and a lot more candidates...
Run Code Online (Sandbox Code Playgroud)
为什么?模板未使用.它有关系吗?
编辑:这个解决了.我不得不返回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;
}
Run Code Online (Sandbox Code Playgroud)
如果我知道使用模板类型.g ++可以编译它,但然后以异常终止.
terminate called after throwing an instance of 'std::bad_cast'
what(): std::bad_cast
Run Code Online (Sandbox Code Playgroud)
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
}
Run Code Online (Sandbox Code Playgroud)
这会为您的程序注入未定义的行为.根据C++ 11标准的第6.6.3/1段,事实上:
[...]离开函数末尾相当于没有值的返回; 这会导致值返回函数中的未定义行为.
关于你的第一个问题:
一旦修复,你的代码就可以了,VC9附带的标准库的实现可能有一个bug.
实际上,编译器应该operator <<在arguments(std)的命名空间和调用的命名空间(全局命名空间)中查找符合条件的重载.只要您的运算符在全局命名空间中定义并且语句cout << s_v位于全局命名空间中,重载解析就应该成功地选择您的重载.
关于你的第二个问题:
为什么?模板未使用.它有关系吗?
这很简单:编译器无法T从函数参数中推导出来,因此除非您明确指定它,否则会导致编译错误.但是,明确指定模板参数意味着执行类似以下操作的操作,这非常接近于无意义:
::operator << <void>(std::cout, s_v);
Run Code Online (Sandbox Code Playgroud)
在C++ 11中,您可以指定一个默认参数T,这会使函数调用合法,然后再次出错,出于什么目的?
关于你的第三个问题:
当T在推导的上下文中的至少一个函数参数的类型中使用时,编译器将允许从函数参数中推导出它(在这种情况下,它将推导出T = std::string,并且您不必明确指定它).
结论:
总而言之:在添加必要的return声明之后,程序的第一个和第三个版本是合法的并且有意义,而第二个版本则没有,也没有.
| 归档时间: |
|
| 查看次数: |
3547 次 |
| 最近记录: |