模板重载ostream运算符

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完成所有这些.不编译其中任何一个.

有人可以帮我澄清这件事吗?谢谢.

And*_*owl 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
}
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声明之后,程序的第一个和第三个版本是合法的并且有意义,而第二个版本则没有,也没有.