How to avoid specific #ifdef in multi - platform qt code?












1














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);
}
}









share|improve this question


















  • 1




    It's not true that "#ifdef is harmful". It's a matter of taste and depends on the particular application and situation. I wouldn't worry about this unless it's causing a real problem. You're gonna blow up your code in size just for some dogma.
    – The Quantum Physicist
    Nov 22 at 14:40


















1














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);
}
}









share|improve this question


















  • 1




    It's not true that "#ifdef is harmful". It's a matter of taste and depends on the particular application and situation. I wouldn't worry about this unless it's causing a real problem. You're gonna blow up your code in size just for some dogma.
    – The Quantum Physicist
    Nov 22 at 14:40
















1












1








1







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);
}
}









share|improve this question













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);
}
}






c++ qt cross-platform multiplatform






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 22 at 14:24









devjb

979




979








  • 1




    It's not true that "#ifdef is harmful". It's a matter of taste and depends on the particular application and situation. I wouldn't worry about this unless it's causing a real problem. You're gonna blow up your code in size just for some dogma.
    – The Quantum Physicist
    Nov 22 at 14:40
















  • 1




    It's not true that "#ifdef is harmful". It's a matter of taste and depends on the particular application and situation. I wouldn't worry about this unless it's causing a real problem. You're gonna blow up your code in size just for some dogma.
    – The Quantum Physicist
    Nov 22 at 14:40










1




1




It's not true that "#ifdef is harmful". It's a matter of taste and depends on the particular application and situation. I wouldn't worry about this unless it's causing a real problem. You're gonna blow up your code in size just for some dogma.
– The Quantum Physicist
Nov 22 at 14:40






It's not true that "#ifdef is harmful". It's a matter of taste and depends on the particular application and situation. I wouldn't worry about this unless it's causing a real problem. You're gonna blow up your code in size just for some dogma.
– The Quantum Physicist
Nov 22 at 14:40














2 Answers
2






active

oldest

votes


















1














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, ifdefing 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).






share|improve this answer































    1














    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 ifdefing 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






    share|improve this answer























    • That'd be just moving "ifdefs" up the chain into the project file. Not that it's somehow worse or better.
      – Dan M.
      Nov 22 at 15:00












    • I wanted to separate the implementations. Im aware that this is a valid approach. But I am concerned about the header because the definitions are different, too, not only the implementations.
      – devjb
      Nov 22 at 15:36










    • If the definitions are different you can use pImpl idiom to separate the implementation details of a class: cpppatterns.com/patterns/pimpl.html
      – Peter
      Nov 22 at 22:01










    • @devjb: I've put this extension into the answer.
      – Peter
      Nov 23 at 9:25











    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53433029%2fhow-to-avoid-specific-ifdef-in-multi-platform-qt-code%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    1














    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, ifdefing 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).






    share|improve this answer




























      1














      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, ifdefing 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).






      share|improve this answer


























        1












        1








        1






        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, ifdefing 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).






        share|improve this answer














        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, ifdefing 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).







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Nov 22 at 14:35

























        answered Nov 22 at 14:29









        Dan M.

        1,94011123




        1,94011123

























            1














            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 ifdefing 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






            share|improve this answer























            • That'd be just moving "ifdefs" up the chain into the project file. Not that it's somehow worse or better.
              – Dan M.
              Nov 22 at 15:00












            • I wanted to separate the implementations. Im aware that this is a valid approach. But I am concerned about the header because the definitions are different, too, not only the implementations.
              – devjb
              Nov 22 at 15:36










            • If the definitions are different you can use pImpl idiom to separate the implementation details of a class: cpppatterns.com/patterns/pimpl.html
              – Peter
              Nov 22 at 22:01










            • @devjb: I've put this extension into the answer.
              – Peter
              Nov 23 at 9:25
















            1














            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 ifdefing 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






            share|improve this answer























            • That'd be just moving "ifdefs" up the chain into the project file. Not that it's somehow worse or better.
              – Dan M.
              Nov 22 at 15:00












            • I wanted to separate the implementations. Im aware that this is a valid approach. But I am concerned about the header because the definitions are different, too, not only the implementations.
              – devjb
              Nov 22 at 15:36










            • If the definitions are different you can use pImpl idiom to separate the implementation details of a class: cpppatterns.com/patterns/pimpl.html
              – Peter
              Nov 22 at 22:01










            • @devjb: I've put this extension into the answer.
              – Peter
              Nov 23 at 9:25














            1












            1








            1






            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 ifdefing 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






            share|improve this answer














            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 ifdefing 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







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Nov 23 at 9:24

























            answered Nov 22 at 14:53









            Peter

            62618




            62618












            • That'd be just moving "ifdefs" up the chain into the project file. Not that it's somehow worse or better.
              – Dan M.
              Nov 22 at 15:00












            • I wanted to separate the implementations. Im aware that this is a valid approach. But I am concerned about the header because the definitions are different, too, not only the implementations.
              – devjb
              Nov 22 at 15:36










            • If the definitions are different you can use pImpl idiom to separate the implementation details of a class: cpppatterns.com/patterns/pimpl.html
              – Peter
              Nov 22 at 22:01










            • @devjb: I've put this extension into the answer.
              – Peter
              Nov 23 at 9:25


















            • That'd be just moving "ifdefs" up the chain into the project file. Not that it's somehow worse or better.
              – Dan M.
              Nov 22 at 15:00












            • I wanted to separate the implementations. Im aware that this is a valid approach. But I am concerned about the header because the definitions are different, too, not only the implementations.
              – devjb
              Nov 22 at 15:36










            • If the definitions are different you can use pImpl idiom to separate the implementation details of a class: cpppatterns.com/patterns/pimpl.html
              – Peter
              Nov 22 at 22:01










            • @devjb: I've put this extension into the answer.
              – Peter
              Nov 23 at 9:25
















            That'd be just moving "ifdefs" up the chain into the project file. Not that it's somehow worse or better.
            – Dan M.
            Nov 22 at 15:00






            That'd be just moving "ifdefs" up the chain into the project file. Not that it's somehow worse or better.
            – Dan M.
            Nov 22 at 15:00














            I wanted to separate the implementations. Im aware that this is a valid approach. But I am concerned about the header because the definitions are different, too, not only the implementations.
            – devjb
            Nov 22 at 15:36




            I wanted to separate the implementations. Im aware that this is a valid approach. But I am concerned about the header because the definitions are different, too, not only the implementations.
            – devjb
            Nov 22 at 15:36












            If the definitions are different you can use pImpl idiom to separate the implementation details of a class: cpppatterns.com/patterns/pimpl.html
            – Peter
            Nov 22 at 22:01




            If the definitions are different you can use pImpl idiom to separate the implementation details of a class: cpppatterns.com/patterns/pimpl.html
            – Peter
            Nov 22 at 22:01












            @devjb: I've put this extension into the answer.
            – Peter
            Nov 23 at 9:25




            @devjb: I've put this extension into the answer.
            – Peter
            Nov 23 at 9:25


















            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.





            Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


            Please pay close attention to the following guidance:


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53433029%2fhow-to-avoid-specific-ifdef-in-multi-platform-qt-code%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Berounka

            Sphinx de Gizeh

            Different font size/position of beamer's navigation symbols template's content depending on regular/plain...