Как избежать специфического #ifdef в многоплатформенном коде qt? - PullRequest
0 голосов
/ 22 ноября 2018

У меня есть класс прослушивателя входа QT, который сигнализирует stdin входы в работающем QCoreApplication.Я хочу использовать это как в Windows, так и в Linux.

Мой текущий подход заключается в использовании #ifdef Q_OS_WIN внутри обоих заголовков и cpp для выполнения кода, специфичного для платформы.Как я знаю, что #ifdef считается вредным, и его следует избегать, я хочу реорганизовать его таким образом, чтобы у меня был один единственный заголовочный файл inputlistener.h и позволить системе сборки выбирать между определенными windows/inputlistener.cpp или linux/inputlistener.cppМожет быть, с дополнительным inputlistener_global.cpp, который содержит код, который не зависит от платформы.

Однако я не могу найти решение, как убрать #ifdef в заголовке.

Как мне этого добиться?

Вот мой нынешний подход:

#inputlistener.h

#ifndef INPUTLISTENER_H
#define INPUTLISTENER_H

#include <QtCore>

class inputlistener : public QObject {
    Q_OBJECT

private:
#ifdef Q_OS_WIN
    QWinEventNotifier* m_notifier;
#else
    QSocketNotifier* m_notifier;
#endif

signals:

    void inputeventhappened(int keycode);

private slots:

    void readyRead();

public:
    inputlistener();
};

#endif // INPUTLISTENER_H

#inputlistener.cpp

#include "inputlistener.h"
#include "curses.h"

#ifdef Q_OS_WIN
#include <windows.h>
#endif

inputlistener::inputlistener()
{
#ifdef Q_OS_WIN
    m_notifier = new QWinEventNotifier(GetStdHandle(STD_INPUT_HANDLE));
    connect(m_notifier, &QWinEventNotifier::activated
#else
    m_notifier = new QSocketNotifier(0, QSocketNotifier::Read, this);
    connect(m_notifier, &QSocketNotifier::activated
#endif
        ,
        this, &inputlistener::readyRead);

    readyRead(); // data might be already available without notification
}

void inputlistener::readyRead()
{
    // It's OK to call this with no data available to be read.
    int c;
    while ((c = getch()) != ERR) {
        emit inputeventhappened(c);
    }
}

Ответы [ 2 ]

0 голосов
/ 22 ноября 2018

Вы можете создать отдельные EventListener.cpp файлы для windows и unix и поместить эти файлы в такие подкаталоги, как (win, linux).В make-файл или в файл проекта вы можете добавить один файл реализации, основанный на текущей платформе.Компилятор скомпилирует только один файл для текущей платформы.

С помощью этого метода вы можете избежать ifdef ing полностью.

Если определения различны, вы можете использовать pImpl идиома для разделенияПодробности реализации класса: https://cpppatterns.com/patterns/pimpl.html

0 голосов
/ 22 ноября 2018

Вы можете создать WinEventListener и UnixEventListener (или что-то еще), каждый из которых использует свою собственную реализацию (вместо того, чтобы пытаться встроить ее в одну с помощью ifdefs), каждый из которых реализует общий интерфейс Listener (и находится в отдельных файлах).

Затем создайте заводскую функцию, которая будет возвращать прослушиватель, соответствующий ОС.То, что у них будет только одно единственное место, которое может потребовать ifdefs.

Но в целом, ifdef что-то может быть лучшим или единственным способом действий (например, когда вы уже абстрагируете что-то).Условная компиляция - это одно из немногих допустимых / оправданных применений препроцессора (это то, для чего оно было сделано).

Также, в вашем конкретном случае, убедитесь, что в Qt lib нет подходящего кода / класса.Для наиболее распространенных вещей есть вероятность, что абстракция уже существует (или рекомендуемые способы сделать это).

...