通过函数C ++传递stringstream值

时间:2012-05-29 15:48:43

标签: c++ function stringstream

我目前有一个日志系统,它接受char *和var args,然后使用它们来执行printf。这适用于C风格的字符串,但我有点清洁。目前,如果我使用std :: stringstream,我必须在日志系统之外创建stringstream,然后将char *用于stringstream给出的字符串。它看起来像这样:

std::stringstream strStream;
strStream << "The value of x is: " << x;
logging::print( strStream.str().c_str() );

我想要的是将参数传递给函数,就像我直接使用字符串流一样。从用户的角度来看,这看起来像这样:

logging::printStream("The value of x is: " << x);

或者可能是这样的:

logging::printStream("The value of x is: ", x);

有没有办法以这样一种方式使用日志记录,即我可以使用字符串流而不必在日志记录系统的函数之外创建它?

这一点尤其重要,因为我打算创建一个宏来阻止任何函数参数在运输版本中进行编译。如果我必须在它之外创建字符串流并将其传入,宏将无用。从技术上讲,我可以创建一个宏来完成我在这个问题中讨论的字符串流的东西,但是这很麻烦,因为我不会总是使用字符串流与此日志记录,所以我将有一个宏用于标准日志记录,并使用不同的宏来使用其中的字符串流调用宏进行标准日志记录。

5 个答案:

答案 0 :(得分:1)

以下按预期工作(已测试 - 使用您的logging :: print将输出替换为cerr):

#include<sstream>
#include<iostream>

class StringstreamLogger {
private:
    std::stringstream s;

public:
    StringstreamLogger () : s (std::ios_base::out) {
    }

    ~StringstreamLogger () {
    std::cerr << s.str () << std::endl; // logging::print (s.str ().c_str ());
    }

    std::stringstream& out () {
    return s;
    }
};

int main () {
    StringstreamLogger ().out () << "My log message";
    std::cerr << "Some later output to test for prompt logging (to ensure that logging is not delayed until the end of a block)" << std::endl;
}

答案 1 :(得分:0)

你可以这样写:

print(static_cast<std::ostringstream&>(std::ostringstream() << "The value of x is: " << x).str().c_str());

也许这更符合你的喜好?

答案 2 :(得分:0)

作为起点,你可以......

class Something {
public:
    std::ostream& error() const { ... code to return some std::ostream ... }
};

...

int main () {
    Something something;
    something.error() << "Frobnicate" << 4;
}

稍后您可以使用重载的流操作符添加您自己的代理对象(我认为这比编写从std::ostream派生的您自己的流更容易。)

当然,那里已经有大量的日志记录框架,首先要查看它们。

答案 3 :(得分:0)

我想出了两个HACK解决方案,但它们应该可以工作。第一个不使用范围解析运算符,更安全。第二个使用noop int变量来伪造范围。

#define logging_printStream(token) { std::stringstream o; o << token; logging::print(o.str().c_str()); }

namespace logging { int noop; }
#define printStream(token) noop = 0; { std::stringstream o; o << token; logging::print(o.str().c_str()); }

int main(int argc, const char** argv)
{
    int i = 1;

    // MORE SAFE
    logging_printStream(i)
    logging_printStream("is this magic? " << (i ? "yes" : "no"))

    // LESS SAFE
    logging::printStream(i)
    logging::printStream("is this magic? " << (i ? "yes" : "no"))
}

由于17.6.4.3.2

,我将logging__printStream更新为logging_printStream
  

17.6.4.3.2全局名称[global.names]

     

某些名称和功能签名集始终保留给实现:

     
      
  • 包含双下划线_ _ 或以下划线后跟大写字母(2.12)开头的每个名称都保留给实现以供任何使用。
  •   
  • 以下划线开头的每个名称都保留给实现,以用作全局命名空间中的名称。
  •   

由于3.6.1

,我单独留下了main的声明
  

3.6.1主要功能[basic.start.main]

     

程序应包含一个名为main的全局函数,它是程序的指定开始。实现定义是否需要独立环境中的程序来定义主函数。实现不应预定义主函数。此功能不应过载。 它的返回类型应为int类型,否则其类型为实现定义。

答案 4 :(得分:0)

重载输出流操作符的自定义类型怎么样?

struct logger
{
    std::stringstream ss_;

    template <typename T>
    friend logger& operator << (logger& l, T const& t) 
    {
    #ifdef DEBUG_MODE
        l.ss_ << t;
    #endif

        return l;
    }

    ~logger()
    {
    #ifdef DEBUG_MODE
        // output ss_.str().c_str() to your logger.
    #endif
    }
};

然后只要你需要记录输出

logger log;
log << "Log this stuff: " << x << '\n';