Reputation: 312
I have a QT input listener class, that signals stdin
inputs in a running QCoreApplication
. I want to use that on both windows and linux.
My current approach is to use #ifdef Q_OS_WIN
inside both header and cpp to execute the platform-specific code. As I know, that #ifdef
is considered harmful and should be avoided, I want to refactor this in a manner where I have one single header file inputlistener.h
and let the build system choose between a specific windows/inputlistener.cpp
or linux/inputlistener.cpp
, maybe with an additional inputlistener_global.cpp
that holds the code, which is not platform specific.
However, I can't find a solution, how to get the #ifdef
in the header out of the way.
How can I achieve that?
Here is my current approach:
#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);
}
}
Upvotes: 2
Views: 1644
Reputation: 1611
You can create separate EventListener.cpp
files for windows
and unix
and put these files into subdirectories like (win
, linux
). To the makefile or to the projectfile you can add one implementation file based on the current platform. The compiler will compile just one file for the current platform.
With this method you can avoid ifdef
ing totally.
If the definitions are different you can use pImpl
idiom to separate the implementation details of a class: https://cpppatterns.com/patterns/pimpl.html
Upvotes: 2
Reputation: 4052
You can create WinEventListener
and UnixEventListener
(or something else) each using it's own implementation (instead of trying to fit it into one via ifdefs), each implementing common Listener
interface (and residing in separate files).
Then, have a factory function that'd return listener appropriate to OS. That they there would be only one single place that might require ifdefs.
But in general, ifdef
ing something might be the best or the only course of action (e.g. when you already abstracting something). Conditional compilation is one of the few valid/justified usages of preprocessor (it's what it was made for).
Also, in your particular case, be sure there is not already appropriate code/class in Qt lib. For most common stuff chances are there is already existing abstraction (or recommended ways to do that).
Upvotes: 1