使用运算符 << 的日志记录功能

Logging function which uses operator <<

我想编写一个日志记录函数,应该像这样使用:

log(__FILE__) << "My message containing integer: " << 123 << " and double: " << 1.2;

这应该打印以下行,立即添加 endl 和刷新:

main.cpp: My message containing integer: 123 and double: 1.2

我(简化)实现该功能的尝试:

class Writer
{
public:
    template<typename T>
    Writer & operator<<(T t)
    {
        cout << t << endl;
        cout.flush();
        return (*this);
    }
};

Writer log(const char* fileName)
{
    cout << fileName << ": ";
    return Writer();
}

int main(int argc, const char *argv[])
{
    log(__FILE__) << "My message containing integer: " << 123 << "and double: " << 1.2;
    return 0;
}

我的问题是,由于运算符的 L-R 结合性<<,输出为:

main.cpp: My message containing integer:

123

and double:

1.2

有什么方法可以实现这个功能,或者我的使用需求是不是实现不了?

理想情况下,我想使用纯 C++03(即没有 C++11 功能、boost 和非标准库)。

L-R 关联性与您的问题无关(如果您谈论换行符)。问题是因为您在每次写入后都使用 endl 。你不需要它(如果你这样做,那么你就不需要刷新,因为 endl 已经刷新了输出)。

您的问题的简单解决方案:

class Writer
{
public:
    template<typename T>
    Writer & operator<<(T t)
    {
        cout << t;
        return (*this);
    }

    ~Writer()
    {
        try {
            cout << endl;
        }
        catch (...) {
            // You have to make sure that no
            // exception leaves destructor
        }
    }
};

同样值得注意的是,您的方法并不是真正可扩展的:不可能在多线程环境中使用您的代码。假设有两个线程正在写入您的日志记录:

Thread 1: log(__FILE__) << "a" << "b" << "c";
Thread 2: log(__FILE__) << "a" << "b" << "c";

在这里您可以很容易地在您的日志文件中得到一条消息 "aabbcc\n\n",这是非常不受欢迎的。

为了避免这种情况,您可以在 log() 函数中有一个静态互斥对象,并将其传递给 Writer 构造函数。然后你必须在构造函数中锁定它并在析构函数中解锁它。它将保证不同条目并发写入的同步。