Russian Qt Forum

Qt => Общие вопросы => Тема начата: ammaximus от Ноябрь 08, 2013, 13:09



Название: Хитрые макросы QLogCat
Отправлено: ammaximus от Ноябрь 08, 2013, 13:09
QLogCat - мой отладчик для работы через сеть. Сочетает в себе элементы QDebug и LogCat.

Код:
// Макроконтур
#define qlc MacroCall()
#define qlcv MacroCall(QLC::Verbose)
#define qlcd MacroCall(QLC::Debug)
#define qlci MacroCall(QLC::Info)
#define qlcw MacroCall(QLC::Warning)
#define qlce MacroCall(QLC::Error)
#define qlca MacroCall(QLC::Assert)
#define qlcf MacroCall(QLC::Fatal)

class QLCSHARED_EXPORT QLC
{
public:
    // Уровень сообщения
    enum LevelType{
        Verbose=0,  // Временное отладочное сообщение (не должно быть фиксировано)
        Debug=1,    // Отладка
        Info=2,     // Информирующее сообщение
        Warning=3,  // Предупреждение
        Error=4,    // Ошибка
        Assert=5,   // Утверждение
        Fatal=6     // Фатальная ошибка
    };

    QLC(QString file, int line, LevelType type, QString log = QLC_DEFTAG);  // Создание объекта
    ~QLC(); // То самое место, которое отправляет по завершению цепочки <<

    QLC& operator<<(const QVariant var);
};

class QLCSHARED_EXPORT MacroCall
{
    QLC::LevelType level;
public:
    MacroCall()
        :level(QLC::Debug){}

    MacroCall(QLC::LevelType l)
        :level(l){}

    QLC operator()(){
        return QLC(__FILE__, __LINE__, level);
    }
    QLC operator()(QString log){
        return QLC(__FILE__, __LINE__, level, log);
    }
};

#endif // QLC_H
qlc - библиотека QLogCat. Отправка сообщений осуществляется через вызов макросов qlc или qlcX, где Х - уровень сообщения. Макросы подставляют вместо себя объект MacroCall, у которого перегружена операция (). Конструктор MacroCall получает параметр Х и запоминает его. Затем, в зависимости от набора аргументов, оператор () создает нужный QLC. Чтобы послать сообщение в QLC используется <<.

Использование
Код:
qlc("Logname") << "Hello";

    //qlce("NotWorkLog") << "Message";
    //MacroCall(QLC::Error)("NotWorkLog") << "Message";

    MacroCall a(QLC::Error);
    a("DasCool") << "That's work!";

Итак проблема. Закомментированный код не работает, но если развернуть его на две части все ок. Что можно сделать с ()() ???

Ошибка invalid use of qualifid-name


Название: Re: Хитрые макросы QLogCat
Отправлено: Bepec от Ноябрь 08, 2013, 15:03
В первом исполняется конструктор и он не в курсах что ты там делаешь дальше с операторами. Это ж конструктор.
А если разложить, то конструктор создаёт объект и вызывает у объекта оператор скобочек.


Название: Re: Хитрые макросы QLogCat
Отправлено: ammaximus от Ноябрь 08, 2013, 15:09
Мне не понятно, два конструктора, с параметром и без, в одном классе, написаны подряд.
Так работает
Код:
MacroCall()("NotWorkLog") << "Message";
Так нет
Код:
MacroCall(QLC::Error)("NotWorkLog") << "Message";


Название: Re: Хитрые макросы QLogCat
Отправлено: ammaximus от Ноябрь 09, 2013, 12:56
Минимальный нерабочий код в студию:
Код:
#include <QVariant>
#include <QDebug>

class QLC
{
public:
// Error types
    enum LevelType{
        Debug=0,  // Debug
        Error=1,  // Error
        WTF = 2   // WTF???
    } level;

    QString logger;

// Constructors
    QLC(QLC::LevelType l)
        :level(l), logger(":")
    {}

    QLC(QLC::LevelType l, QString log)
        :level(l), logger(log)
    {}

// OPERATOR <<
    QLC& operator<<(const QVariant var){
        qDebug() << "(" + QString::number(level) + ")" << logger << var;
    }
};

class MacroCall
{
    QLC::LevelType level;
public:
    MacroCall()
        :level(QLC::Debug){}

    MacroCall(int i)
        :level(QLC::WTF){}

    MacroCall(QLC::LevelType l)
        :level(l){}

    QLC operator()(){
        return QLC(level);
    }
    QLC operator()(QString log){
        return QLC(level, log);
    }
};

int main(int argc, char*argv[])
{
    MacroCall()("WorkLog") << "No level, yes logname";
    MacroCall(QLC::Error)() << "No logname, yes level";

    MacroCall a(QLC::Error);
    a("WorkLog") << "Logname and level at different lines";

    // GET READY!
    // INT as level and logname:
    MacroCall(2)("WorkLog") << "WTF?? It works!";

    //MacroCall(QLC::WTF)("NotWorkLog") << "It's not work!!!!!!";
    // NOT WORK: error: invalid use of qualified-name 'QLC::WTF'
    // Qt 4.8.3

    return 0;
}


Название: Re: Хитрые макросы QLogCat
Отправлено: m_ax от Ноябрь 09, 2013, 15:40
Непонятно зачем вообще MacroCall обязательно должен быть классом?

Можно, например, так:
Код
C++ (Qt)
template <QLC::LevelType level = QLC::Debug>
QLC MacroCall(const QString & log = QString()) {
   return QLC(level, log);
}
 
...
 
MacroCall<QLC::Error>("WorkLog") << " message ";
MacroCall<>("WorkLog") << " message ";
 


Название: Re: Хитрые макросы QLogCat
Отправлено: ammaximus от Ноябрь 10, 2013, 14:43
Искать решение за пределами проблемы  :D Когда-нибудь и я так буду.

Обнаружили интересный момент: http://stackoverflow.com/questions/19874867/enum-in-constructor-qt-c

Проблему уже решил отказом от использования енумов:

Код:
#define qlcv MacroCall(__FILE__, __LINE__, 0)
#define qlcd MacroCall(__FILE__, __LINE__, 1)
#define qlci MacroCall(__FILE__, __LINE__, 2)
#define qlcw MacroCall(__FILE__, __LINE__, 3)
#define qlce MacroCall(__FILE__, __LINE__, 4)
#define qlca MacroCall(__FILE__, __LINE__, 5)

 MacroCall(QString f, int l, int type)
        :level(QLC::LevelType(type)), file(f), line(l){}


Шаблоны круто, будет время - перепишу, для общего развития