我正在尝试仅为我自己做一个简单的日志库。我知道有几次,但是我没有找到适合我的应用程序的任何仅 header 的,小巧且非常“c++”的日志库。

目前,我有以下语法:

logger << debug << "A debug message" << end; //debug and end is my custom manipulators

我已经实现了所有必需的operator <
刚才我有以下简短的代码:
template <typename Type>
Logger & Logger::operator<<(const Type & message)
{
    if(this->get_message_level() <= this->get_severity())
    {
        BOOST_FOREACH(std::ostream* stream, this->_sinks)
        {
            *stream << message;
        }
    }
    return *this;
}

Logger & Logger::operator<< (Logger & (*pf)(Logger&))
{
    return pf(*this);
}

Logger & debug(Logger& logger)
{
    logger.lock();
    logger.set_severity(7);
    //...
    return logger;
}

Logger & end(Logger& logger)
{
    logger << std::endl;
    logger.unlock();
    return logger;
}

提前致谢。

最佳答案

可能会有些棘手,具体取决于您愿意妥协的因素
接受语法。如果您真的想支持一切
输出到ostream可以,那么就可以做到最好(就我而言
知道)是包装类,大致如下:

class Logger
{
    std::ostream* myDest;
public:
    //  Appropriate constructors...
    template<typename T>
    Logger& operator<<( T const& obj )
    {
        if ( myDest != NULL )
            (*myDest) << obj;
        return *this;
    }
};

如果关闭日志记录(Logger::myDest == NULL),则没有
转换代码将执行,但您仍将评估每个
论点。以我的经验,这通常不是问题,因为大多数
的参数是字符串文字或简单变量,但是
这不是总计0的费用。它也有潜在的缺点
传播的类型不是std::ostream&(尽管我从未发现
这在实践中是一个问题)。

一个更棘手的解决方案是使用以下宏:
#define logger loggerInstance != NULL && (*loggerInstance)

这仍将允许大多数实际使用相同的语法
(因为&&运算符的优先级很低),但可能会失败
有人试图变得太聪明并嵌入日志记录的情况
输出更复杂的表达式。除了不做
转换,如果打开日志记录,则甚至不评估参数
关。

最后,如果您接受其他语法,则可以编写如下内容:
#ifndef NDEBUG
#define LOG(argList) logger << argList
#else
#define LOG(argList)
#endif

这要求用户编写LOG("x = " << x)而不是log <<"x = " << x,并且如果要打开登录名,则需要重新编译,
但这是我知道的唯一解决方案,如果记录日志,它的成本绝对为0
已关闭。

以我的经验,大多数应用程序都可以支持第一个解决方案。在一个
在极少数情况下,您可能需要使用第二种方法;而且我从未见过
性能要求第三的应用程序。

请注意,即使是第一个,您也可能要使用宏
获取记录器实例,以便自动插入__FILE____LINE__,在第二个中,您可能仍想使用
包装器类,以确保析构函数中的刷新;如果
应用程序是多线程的,在所有情况下都需要包装器,
为了使输出的整个序列原子化。

关于c++ - 停止求值运算符<<,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/8602546/

10-12 14:12