C++重载

Ana*_*and 1 c++ stream visual-studio-2010 visual-c++

以下代码给出了编译错误.谁能告诉我为什么?

class mytype {
public:
    int value;
    mytype(int a) {
        value = a;
    }
    friend ostream& operator<<(ostream& stream, const mytype& a) {
        stream << a.value;//works
        return stream;
    }
    friend ostringstream& operator<<(ostringstream& stream, const mytype& a) {
        stream << (a.value);//compilation error
        return stream;
    }
};
Run Code Online (Sandbox Code Playgroud)

错误:

错误C2027:使用未定义类型'std :: basic_ostringstream <_Elem,_Traits,_Alloc>'

在确定:

错误C2666:'operator <<':18次重载具有类似的转换

最终修复:

将构造函数声明为显式.然后在MSVC上工作.

我想知道为什么.

Pot*_*ter 7

错误C2027:使用未定义类型'std :: basic_ostringstream <_Elem,_Traits,_Alloc>'

你需要#include <sstream>得到[i/o]stringstream班.

关于其他错误

表单重载的问题

ostringstream& operator<<(ostringstream& stream, const mytype& a)
Run Code Online (Sandbox Code Playgroud)

是它ostringstream 完全匹配.为什么要有更准确的重载是一件坏事?从标准,§13.3.3/ 1-2:

如果对于所有参数i,ICSi(F1)不是比ICSi(F2)更差的转换序列,则可行函数F1被定义为比另一个可行函数F2更好的函数...

如果只有一个可行的函数比所有其他可行函数更好的函数,则它是由重载决策选择的函数; 否则电话会形成不良

因此,如果operator<<( ostream &, int )并且operator<<( ostringstream &, mytype const & )都是候选者stream << value,前者int完全没有转换,但后者ostringstream完全匹配.因此,对于所有论点都不能"不差",也不能选择候选人.

但是由于存在漏洞,代码有效的.您的重载根本不是候选者,除非您在函数调用中实际使用了类型.在friend类块中声明/定义一个类时,它不会将它引入任何命名空间范围; 它只是将它与类范围相关联,如果该类类型描述了传递的参数之一,则允许找到它.

标准有关于朋友声明的说法,尽管它在另一部分(14.6.5):

朋友声明不会在任何范围内引入新名称......

因此,MSVC试图很好,并主动将您的朋友介绍到其封闭的命名空间.打击MSVC.

然而,当我试图添加一个等同于MSVC"免费"的声明时,Comeau和GCC很好地解决了由此产生的超载冲突 - 对它们进行攻击.或者是吗?事实证明,重载调用发生在文件中的早于我推荐的声明.如果我之前 移动声明class mytype {(需要向前声明mytype),那么两者都适当地抱怨模糊性.

根据标准的§3.3-3.4,在命名空间范围内声明之前使用重载似乎很好.所以GCC和Comeau实际上都在右边.声明点就在声明对象的名称之后.(最后我检查过,自引用函数声明仍然可以使GCC崩溃.)ADL在封闭类之前的某个点调用封闭命名空间中的非限定查找.(3.4.1/8最后一颗子弹,3.4.1/9,3.4.2/2a.)如果朋友没有在课前宣布,那么合法的不是候选人.(7.3.1.2/3)C++不是一门优美的语言吗?

如何在GCC上保留简化示例,但要破坏后续代码.

    friend ostringstream& operator<<(ostringstream& stream, const mytype& a) {
        stream << (a.value);//compilation error
        return stream;
    }
};

ostringstream& operator<<(ostringstream& stream, const mytype& a); // <- here
Run Code Online (Sandbox Code Playgroud)

在这个宣言之后,将不可能写成int一个ostringstream.

如何使用更简单的声明语义统一破坏所有内容.

class mytype; // <- here
              // and here:
inline ostringstream& operator<<(ostringstream& stream, const mytype& a);

class mytype {
public:
Run Code Online (Sandbox Code Playgroud)

根据这一声明,这将是不可能写一intostringstream......包括里面的朋友的声明class mytype {}.

实际解决方案

流类应该是无法区分的.如果你真的想确定一个给定的流是否在内存中输入一个字符串(你不应该),那么最好查看它streambuf返回的内部对象rdbuf(),它实际上执行了I/O gruntwork.如果给定a,即使是通用ostream对象也可以具有ostringstream功能stringbuf.

 if ( typeid( stream.rdbuf() ) == typeid( stringbuf * ) ) {
     // this is effectively a stringstream
 } else {
     // not a stringstream
 }
Run Code Online (Sandbox Code Playgroud)