1

我不知道为什么会出错,但我只是想在 endl 中添加一些“类似”的东西,这样我就可以将 ostringstream 中的内容扔到我们的调试器中。我有以下内容:

class debug_stream_info
{
public:
    debug_stream_info(int errorLine, char *errorFile, int level)
        :m_errorLine(errorLine), m_errorFile(errorFile), m_logLevel(level)
    {
    }

    friend std::basic_ostringstream<char>& operator<<(std::basic_ostringstream<char>& os, debug_stream_info& debug_info);

private:
    int m_errorLine;
    std::string m_errorFile;
    int m_logLevel;

};

std::basic_ostringstream<char>& operator<<(std::basic_ostringstream<char>& os, debug_stream_info& debug_info)
{
    // Write the stream's contents to cpu_debug
    // Deleted custom logging function.  No errors here though

    // Clear the stream for re-use.
    os.str("");
    os.seekp(0);

    return os;
}

int main(int argc, char** argv)
{
    std::ostringstream myout;
    myout << "hey there" << " and some more " << "Numbers!!: " << 435 << 54.2 << " that's good for numbers" << debug_stream_info(__LINE__, __FILE__, LOG_LEVEL);

    return 0;
}

我得到的错误是:error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'debug_stream_info' (or there is no acceptable conversion)对于 main 中的行。这是在VS2008上。

我包括 sstream、iostream 等,并正确设置了命名空间。我没有收到其他错误。我什至尝试用basic_ostreamjust替换所有出现的情况ostringstream,但没有任何区别(我稍后会有一个w_char版本,但我希望首先使用简单的案例)。我在上面的行上做了对象,然后在行上传递了一个完全构造好的对象,错误是完全一样的。我已经更改了第二个参数的签名,也const没有更改。

关于我在这里做错了什么的任何想法?

编辑:因为每个响应似乎都想把它放在那里,我不能使用 std::ostream 因为我希望它只适用于std::ostringstream(and std::basic_ostringstream) 而不是任何类型的输出流。此外,该函数无论如何都不会使用 ostream 编译,因为我正在使用该os.str()方法,它不在 ostream 中,只有子类。

4

3 回答 3

8

您的代码的真正问题是您重载std::ostringstream了而不是std::ostream. 因此,如果您编写以下代码,您的代码将起作用:

debug_stream_info info(/** blah blah**/);

std::ostringstream oss;
oss << info ; //OK

但是,这不起作用:

oss << 1 << info; //ERROR

这是编译错误,因为表达式oss<<1返回的类型对象std::ostream&没有debug_stream_info作为第二个参数的重载。这意味着如果您使用 cast 为:

static_cast<std::ostringstream&>(oss << 1) << info; //OK

那么这应该再次起作用。

所以解决方案是重载std::ostream,而不是std::basic_ostringstream.

此外,第二个参数应该是const &. 这也是您的代码的问题。

所以写这个:

std::ostream& operator<<(std::ostream&, debug_stream_info const &);
                                                        //^^^^^^^ note this

第二个参数应该是const &这样您就可以将临时对象写入流。

于 2012-04-30T16:05:59.020 回答
1

debug_stream_info(__LINE__, __FILE__, LOG_LEVEL);正在创建未返回任何内容的未命名对象,因此出现错误

#include <iostream>
#include <cstdio>
#include <sstream>
using namespace std;

class debug_stream_info
{
public:
    debug_stream_info(int errorLine, char *errorFile, int level)
        :m_errorLine(errorLine), m_errorFile(errorFile), m_logLevel(level)
    {
    }

    friend std::basic_ostringstream<char>& operator<<(std::basic_ostringstream<char>& os, debug_stream_info& debug_info);
    std::ostringstream& fun(std::ostringstream& os)
    {
        os<<"Ashish"<<endl;
        return os;
    }
private:
    int m_errorLine;
    std::string m_errorFile;
    int m_logLevel;

};

std::basic_ostringstream<char>& operator<<(std::basic_ostringstream<char>& os, debug_stream_info& debug_info)
{
    // Write the stream's contents to cpu_debug
    // Deleted custom logging function.  No errors here though

    // Clear the stream for re-use.
//    os.str("");
//    os.seekp(0);

    return os;
}

int main(int argc, char** argv)
{

    std::ostringstream myout, test;
        myout << "hey there" << " and some more " << "Numbers!!: " << 435 << 54.2 << " that's good for numbers"
         << debug_stream_info(1, "/home/ashish/test", 1).fun(test);
    return 0;
}
于 2012-04-30T16:11:58.183 回答
1

Nawaz 已经非常清楚地解释了为什么您会收到错误消息。在这种情况下,通常的解决方案是定义自己的流类型,与std::istream. 类似于以下内容:

class DebugStream
{
    std::ostringstring* collector;

public:
    template <typename T>
    DebugStream& operator<<( T const& value )
    {
        if ( collector != NULL ) {
            *collector << value;
        }
        return *this;
    }
};

对此有无限的变化;在您的情况下,您可以为您的类型添加一个非模板成员函数;更有可能的是,您会添加一个采用相同参数的构造函数:

DebugStream( int lineNumber, std::string const& filename, int logLevel )
    : collector( isActive( logLevel ) ? new std::ostringstream : NULL )
{
    //  Initial insertion of lineNumber, filename, timestamp...
}

您还可以添加一个析构函数,它以原子方式将收集的数据刷新到文件中(或发送电子邮件,或将其写入系统日志,或其他)。(对此要非常小心。即使日志记录失败,您也不希望异常从析构函数中逃脱。)

最后,您可能想要使用自定义流缓冲区,而不是 stringstream. 假设将分配的缓冲区从一个实例保留到下一个实例。如果您这样做,而不是new每次都读取流,您可能会从表中获取一个实例,按日志级别索引(并从配置文件初始化)。

于 2012-04-30T16:58:45.117 回答