C++ qMessageloger魔法是如何工作的?

C++ qMessageloger魔法是如何工作的?,c++,qt,logging,C++,Qt,Logging,我正在为QT应用程序开发一个记录器框架。出于理解和学习的目的,我没有直接使用QMessageLogger。关于一个QMessageLogger功能,有一件事我很想在我的记录器中使用,但我不知道它是如何工作的。以qDebug宏为例: #define qDebug QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC).debug 可以通过两种方式调用此函数: 第一条路: 第二种方式: qDebug()

我正在为QT应用程序开发一个记录器框架。出于理解和学习的目的,我没有直接使用
QMessageLogger
。关于一个
QMessageLogger
功能,有一件事我很想在我的记录器中使用,但我不知道它是如何工作的。以
qDebug
宏为例:

#define qDebug QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC).debug
可以通过两种方式调用此函数: 第一条路:

第二种方式:

qDebug() << "abc = " << abc;

首先,您需要了解以下内容

QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC).debug
上面的行构造了一个
QMessageLogger
实例,并立即访问其调试成员。因为它是一个宏,所以在它之后写什么代码也很重要

如果查看什么是
QMessageLogger::debug
,您将看到四个重载,其中前两个与您的问题相关:

void debug(const char *msg, ...) const Q_ATTRIBUTE_FORMAT_PRINTF(2, 3);
QDebug debug() const;
QDebug debug(const QLoggingCategory &cat) const;
QDebug debug(CategoryFunction catFunc) const;
现在事情应该很简单了。如果调用
qDebug(“abc=%u”,abc)
,则调用的是第一个重载,展开的宏如下所示:

QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC).debug("abc = %u", abc)
QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC).debug() << "abc = " << abc;
多少等于

QMessageLogger temp(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC);
temp.debug("abc = %u", abc);
QMessageLogger temp(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC);
QDebug anotherTemp = temp.debug();
anotherTemp << "abc = " << abc;
在第二种情况下,调用一个返回对象的重载<代码>QDebug已重载。展开的宏如下所示:

QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC).debug("abc = %u", abc)
QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC).debug() << "abc = " << abc;

qmessageloger(QT\u MESSAGELOG\u文件,QT\u MESSAGELOG\u行,QT\u MESSAGELOG\u FUNC).debug(),如果我的标准方法是:
void print(MLL::ELogLevel lvl,const char*text,…)
,我是否应该添加一个重载,看起来可能是这样的:
QTextStream print(MLL::ELogLevel lvl)const?@ukaszPrzeniosło我有点错过了问题的第二部分。我会更新的。你可以做你所做的,但是我只需要在我的日志中重载
operator()
,以及
operator,我会很感激的。因为现在我不知道如何按照我展示的方式来做,因为在pint函数中,我检查记录器是否初始化,如果没有,我返回。但是这里我必须返回一个
QTextStream
,所以我不能返回ie.0。@ukaszPrzeniosło第73行fwd声明,87将op()更改为类内的声明,130定义的op()好的,我想我已经做到了。我添加了一个如下所示的覆盖打印函数:
LoggerHelper cbclouger::print(MLL::ELogLevel lvl)const{return LoggerHelper(lvl);}
。我不确定这是正确的方法,我确定我还没有完全理解这一点,但我很高兴它能起作用。非常感谢@krzaqSide注意:如果您编写C++11并使用C的可变参数,那么您就做错了。我应该如何正确地进行操作?不要使用可变参数。忘记它们的存在。参见,例如,它不是类型安全的,在C++11中是不必要的。你可能会问“C有什么问题”。你链接到的文章探讨了这个问题,是的。
void addNewLogLine(char const* ptr){
    cout << "addNewLogLine: " << ptr << endl;
}
struct LoggerHelper
{
    std::stringstream s;

    explicit LoggerHelper()=default;
    LoggerHelper(LoggerHelper&&) = default;

    ~LoggerHelper(){
        auto str = s.str();
        addNewLogLine(str.c_str());
    }

    template<typename T>
    LoggerHelper& operator<<(T const& val){
        s << val;
        return *this;
    }
};

struct Logger
{
    void operator()(char const* fmt, ...) const {
        char* buf;
        va_list args;
        va_start(args, fmt);
        vasprintf(&buf, fmt, args);
        va_end(args);
        addNewLogLine(buf);
        free(buf);
    }

    LoggerHelper operator()() const {
        return LoggerHelper{};
    }
};