'stringstream'参数顺序问题

'stringstream' argument order trouble

本文关键字:问题 顺序 stringstream 参数      更新时间:2023-10-16

我遇到stringstream的一个奇怪问题。

#include "stdafx.h"
#include "iostream"
#include "sstream"
using namespace std;
struct Test
{
    float f;
};
wstringstream& operator <<( wstringstream& sstream , const Test& test )
{
    sstream << test.f;
    return sstream;
}
int _tmain(int argc, _TCHAR* argv[])
{
    Test a;
    a.f = 1.2f;
    wstringstream ss;
    ss << L"text" << a << endl; // error C2679!
    ss << a << L"text" << endl; // it works well..
    getchar();
    return 0;
}

问题就在这里:

ss << L"text" << a << endl; // error C2679!
ss << a << L"text" << endl; // it works well..

这两个语句之间的唯一区别是参数顺序。为什么第一个语句失败而第二个语句有效?

不要将您的operator<<仅限于使用wstringstream,编写它以使其能够使用任何宽流:

std::wostream& operator <<(std::wostream& sstream, Test const& test)
{
    return sstream << test.f;
}

或与任何流(宽或窄):

template<typename CharT, typename TraitsT>
std::basic_ostream<CharT, TraitsT>&
operator <<(std::basic_ostream<CharT, TraitsT>& sstream, Test const& test)
{
    return sstream << test.f;
}

简短回答

问题是ss << L"text"给你的是std::wostream,而不是std::wstringstream

您只为std::wstringstream创建了一个operator<<,因此下一个操作(您试图在a上执行)将失败。

答案很长

当你写类似的东西时

ss << L"text" << a << endl;

您不是在调用一个有四个参数的函数。

事实上,您正在链接多个操作:

((ss << L"text") << a) << endl;

这之所以有效,是因为每个operator<<操作都返回对原始流对象的引用,因此您可以继续以这种方式链接上的进一步操作。

但是,因为iostreams形成了一个继承层次结构,并且operator<<适用于任何输出流,所以wstringstream上操作的返回类型比wstringstream稍微不那么具体。

事实上,ss << L"text"的求值结果为wostream&wostreamwstringstream的基类之一)。引用仍然指向相同的原始流对象。。。但是它有一个基类类型。

因此,涉及a的第二个操作具有以下活动操作数:

  • wostream&(在LHS上)
  • Test(在RHS上)

但是您没有wostream& operator<<(wostream&, Test const&)。您只创建了一个wstringstream& operator<<(wstringstream& sstream, Test const& test),因此没有匹配项。

因此,事实上,当为宽iostreams创建operator<<时,您应该使其适用于所有wostreams(显然没有理由将其限制为wstringstreams):

wostream& operator<<(wostream& sstream, Test const& test)
{
    sstream << test.f;
    return sstream;
}

更进一步,为什么要把自己限制在宽阔的溪流中?为什么不是普通的呢?

template<typename CharT, typename TraitsT>
std::basic_ostream<CharT, TraitsT>&
operator<<(std::basic_ostream<CharT, TraitsT>& sstream, Test const& test)
{
    sstream << test.f;
    return sstream;
}

现在,您将能够正确地将Test类的对象流式传输到wostreams、ostreams及其所有后代中。