2015-05-26 95 views
-1

我想创建一个用于记录目的的类,其行为与std::cout类似,但会自动将其他信息插入到流中。超载<<运算符并将参数传递给std :: cout

,我想会是这样的一个样本使用(让现在不关心对象和上下文类型,只是假设它们的std :: string):

Logger l; 

l << "Event with object : " << obj << " while in context : " << context; 

那么输出将是:

[timestamp] Event with object : [obj_desc] while in context : [this context][eol][flush] 

我一直在试图用:

template<typename T> 
Logger& operator << (const T& msg){ 
    std::cout << timestamp() << msg << std::endl << std::flush; 
    return *this; 
} 

但似乎std::cout无法解析typename T,并且无法在segfaulting时输出std :: string。

一个可能的解决办法是重载这对所有类型的,但是这是相当恼人的和耗时。

有更好的选择来装饰std::cout输出更多的信息?

编辑:

我现在认识到,end1和冲洗将追加到每个消息哪一种失败的目的,但我仍然有兴趣的总体思路。我更关心追加任意数量的消息的单子语法,而不是<<过载

+2

'std :: endl'已经刷新了流。 – chris

+1

请参阅:[std :: endl的重载处理?](http://stackoverflow.com/q/2212776/14065) –

+0

请提供整个(精简但完整)代码以进行重现。那么,不要解释错误,而是引用它。很可能你正在使用临时或常量的Logger,或试图将一个像std :: endl这样的重载函数放入它中,但没有实际的代码和错误是不可能的。 –

回答

0

您的代码不起作用的原因是因为您尚未对要传递给它的所有内容实施operator<<

本声明:

Logger l; 
l << "Event with object : " << obj << " while in context : " << context; 

基本上是这样做(假设operator<<Logger一员,你的实现意味着它是):

Logger l; 
l.operator<<("Event with object : ").operator<<(obj).operaator<<(" while in context : ").operator<<(context); 

所以,你需要的operator<<单独重载对于字符串,obj,上下文等等。你需要一种方法来指示何时将完整的日志消息刷新到std::cout

我会更喜欢这个建议的内容:

struct LoggerStream 
{ 
    std::ostringstream strm; 

    struct Timestamp 
    { 
    }; 

    ~LoggerStream() 
    { 
     std::string s = strm.str(); 
     if (!s.empty()) 
      std::cout << s << std::flush; 
    } 

    LoggerStream& operator<< (const Timestamp &t) 
    { 
     strm << "[timestamp] "; // format this however you need 
     return *this; 
    } 

    LoggerStream& operator<< (const object &obj) 
    { 
     strm << "[obj_desc]"; // format this however you need 
     return *this; 
    } 

    LoggerStream& operator<< (const context &ctx) 
    { 
     strm << "[this context]"; // format this however you need 
     return *this; 
    } 

    LoggerStream& operator<< (std::ostream&(*f)(std::ostream&)) 
    { 
     if (f == (std::basic_ostream<char>& (*)(std::basic_ostream<char>&)) &std::flush) 
     { 
      std::string s = strm.str(); 
      if (!s.empty()) 
       std::cout << s << std::flush; 
      strm.str(""); 
      strm.clear(); 
     } 
     else 
      strm << f; 

     return *this; 
    } 

    template<typename T> 
    LoggerStream& operator<< (const T& value) 
    { 
     strm << value; 
     return *this; 
    } 
}; 

class Logger 
{ 
    LoggerStream getStream() 
    { 
     LoggerStream strm; 
     strm << Timestamp; 
     return strm; 
    } 
}; 

然后,你可以做这样的事情:

Logger l; 
l.getStream() << "Event with object : " << obj << " while in context : " << context; 
... 
l.getStream() << "Event with object : " << obj << " while in context : " << context; 
... 

Logger l; 
LoggerStream strm = l.getStream(); 
strm << "Event with object : " << obj << " while in context : " << context << std::flush; 
... 
strm << Logger::Timestamp << "Event with object : " << obj << " while in context : " << context << std::flush; 
... 

或者:

struct Logger 
{ 
    std::ostringstream strm; 

    ~Logger() 
    { 
     std::string s = strm.str(); 
     if (!s.empty()) 
      std::cout << "[timestamp] " << s << std::flush; 
    } 

    Logger& operator<< (const object &obj) 
    { 
     strm << "[obj_desc]"; // format this however you need 
     return *this; 
    } 

    Logger& operator<< (const context &ctx) 
    { 
     strm << "[this context]"; // format this however you need 
     return *this; 
    } 

    Logger& operator<< (std::ostream&(*f)(std::ostream&)) 
    { 
     if (f == (std::basic_ostream<char>& (*)(std::basic_ostream<char>&)) &std::flush) 
     { 
      std::string s = strm.str(); 
      if (!s.empty()) 
       std::cout << "[timestamp] " << s << std::flush; 
      strm.str(""); 
      strm.clear(); 
     } 
     else 
      strm << f; 

     return *this; 
    } 

    template<typename T> 
    Logger& operator<< (const T& value) 
    { 
     strm << value; 
     return *this; 
    } 
}; 

Logger() << "Event with object : " << obj << " while in context : " << context; 
... 
Logger() << "Event with object : " << obj << " while in context : " << context; 
... 

Logger l; 
l << "Event with object : " << obj << " while in context : " << context << std::flush; 
... 
l << "Event with object : " << obj << " while in context : " << context << std::flush; 
... 
0

可以肯定超载,如果你想流类,你想要支持的所有数据类型提供operator<<(这可能是“正确”的路要走)但是,如果您只是将日志记录添加到常规流的快捷方式,则可以使用更简单的方法:

#include <iostream> 
#include <iomanip> 
#include <sstream> 
#include <ctime> 
#include <unistd.h> 

#define logcout std::cout << timestamp() 

std::string timestamp(void) { 
    time_t now = time(0); 
    struct tm *tmx = localtime(&now); 
    std::ostringstream oss; 
    oss << '[' 
     << (tmx->tm_year+1900) 
     << '-' 
     << std::setfill('0') << std::setw(2) << (tmx->tm_mon+1) 
     << '-' 
     << std::setfill('0') << std::setw(2) << (tmx->tm_mday) 
     << ' ' 
     << std::setfill('0') << std::setw(2) << (tmx->tm_hour) 
     << ':' 
     << std::setfill('0') << std::setw(2) << (tmx->tm_min) 
     << ':' 
     << std::setfill('0') << std::setw(2) << (tmx->tm_sec) 
     << "] "; 
    return oss.str(); 
} 

int main (int argc, char *argv[]) { 
    logcout << "A slightly\n"; 
    sleep (5); 
    logcout << "sneaky" << " solution\n"; 
    return 0; 
} 

其中输出:

[2015-05-26 13:37:04] A slightly 
[2015-05-26 13:37:09] sneaky solution 

不要被代码的大小所愚弄,我只是提供了一个完整的可编译样本进行测试。而问题的关键是线:

#define logcout std::cout << timestamp() 

,然后可在使用logcout代替std::cout,每出现一个任意字符串(在这种情况下,时间戳,占前缀的流内容大部分代码)。

这不是我所说的最纯粹的纯粹的 C++代码,但如果你的需求基本上是你所说的话,它肯定会有诀窍。

相关问题