我遇到了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..

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

最佳答案

简短答案

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

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

长答案

当你写类似

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

您没有调用带有四个参数的函数。

实际上,您正在链接多个操作:
((ss << L"text") << a) << endl;

之所以可行,是因为每个operator<<操作都返回对原始流对象的引用,因此您可以继续以此方式链接其他操作。

但是,因为iostreams形成了一个继承层次结构,并且因为operator<<适用于任何输出流,所以您对wstringstream进行操作的返回类型比wstringstream更为具体。

实际上, ss << L"text"的计算结果为wostream& (wostreamwstringstream的基类之一)。该引用仍然引用相同的原始流对象...但是它具有基类类型。

因此,涉及a的第二个操作具有以下 Activity 操作数:
  • wostream&(在LHS上)
  • (在RHS上)Test

  • 但是您没有wostream& operator<<(wostream&, Test const&)。您仅创建了wstringstream& operator<<(wstringstream& sstream, Test const& test),所以没有匹配项。

    因此,实际上,当为宽iostream创建一个operator<<时,应该使它适用于所有wostream(显然,没有理由将其限制为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类的对象正确地流式传输到wostreamostream以及它们的所有后代中。

    10-06 01:53