【问题标题】:overload << operator and pass parameters to std::cout重载 << 运算符并将参数传递给 std::cout
【发布时间】:2015-05-26 04:53:30
【问题描述】:

我想创建一个用于记录目的的类,其行为类似于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 并且无法输出std::string,例如在segfaulting 时。

一种可能的解决方案是为所有类型重载它,但这相当烦人且耗时。

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

编辑:

我现在确实意识到 endl 和 flush 将被附加到每条消息中,这会破坏目的,但我仍然对一般想法感兴趣。与&lt;&lt;overload 相比,我更关心附加任意数量消息的单子语法

【问题讨论】:

  • std::endl 已经刷新了流。
  • 请提供完整的(精简但完整的)代码以便重现。然后,不要解释错误,但也要引用它。很可能您在临时或常量 Logger 上使用它,或者尝试将 std::endl 之类的重载函数流式传输到其中,但如果没有实际代码和错误,这是不可能的。
  • Loki,这几乎解决了我的问题,谢谢!

标签: c++ templates c++11 stdout ostream


【解决方案1】:

您的代码不起作用的原因是您没有为要传递给它的所有内容实现operator&lt;&lt;

此声明:

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

基本上是这样做的(假设operator&lt;&lt;Logger 的成员,您的实现暗示它是):

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

因此,您需要为字符串、obj、上下文等单独重载operator&lt;&lt;。并且您需要一种方法来指示何时将完整的日志消息刷新到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;
...

【讨论】:

    【解决方案2】:

    如果你愿意,你当然可以重载流类,为你想要支持的所有数据类型提供operator&lt;&lt;(这可能是“正确”的方法)但是,如果你追求的是快速将日志记录添加到常规流的方法,有一种更简单的方法:

    #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++ 代码,但是,如果您的需求基本上是您所说的,那么它肯定会成功。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-05
      • 1970-01-01
      • 1970-01-01
      • 2018-09-25
      • 2014-07-24
      • 1970-01-01
      相关资源
      最近更新 更多