c++ - 模板重载 ostream 运算符

标签 c++ templates operator-overloading

我正在尝试漂亮地打印一个 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/

相关文章:

C++11线程修改std::list

c++ - 带有 C++11 lambda 的 C 函数指针

c++ - 一次处理所有传递的重载

c++ - 如何在 C++ 中重载赋值运算符?

c++ - STL容器的difference_type typedef

c++ - windows下lapack的使用方法

c++ - 参数包构造函数在类模板中隐藏用户定义的转换

c++ - 错误 LNK2019 : unresolved external symbol "public: __thiscall Signal

c++ - 在模板参数中将枚举转换为 int

C++函数重载