How usable is Qt without its preprocessing step?

C++Qt

C++ Problem Overview


I think it's unreasonable for a library to require preprocessing of my source code with a special tool. That said, several people have recommended the Qt library to me for cross platform GUI development.

How usable is Qt without the preprocessing step?

EDIT: Okay people, I'm not meaning this question as a rip on Qt -- too many Qt fanboys are treating it as if it is. I don't want to discuss the merits of the fact that Qt came up with this preprocessing tool. I understand why the tool is there, and I understand why there are large parts of Qt's design that are built upon the idea of preprocessing.

I've never used Qt, ergo I am in no position to rip on it. But I would much rather pay in writing a small amount of boilerplate myself and not depend on ripping apart my entire build process. I won't use Flex and Bison in my current project for the same reason; if I won't use those tools, I'm definitely not going to use another kind of preprocessing.

So, please don't take me as ripping on Qt. I cannot comment on how nice or not nice it is; I have not used it. I just want to know if it is possible to use it without moc.

C++ Solutions


Solution 1 - C++

Qt doesn't require the use of moc just to use it, it requires that usage if you create a subclass of QObject, and to declare signals and slots in your custom classes.

It's not unreasonable, moc provides features that C++ doesn't have, signals/slots, introspection, etc.

So, to do something minimally advanced, you WILL have to use the moc preprocessor. You either love it, or hate it.

Solution 2 - C++

It's completely usable now. The maintainer of moc has made an alternative with slightly more verbose syntax than ordinary Qt, but it uses standard C++14 so there's no extra step.

It's called 'Verdigris'

(as an aside, moc isn't really a preprocessing step so much as a code generator. The code you write is valid C++, and moc doesn't change any of it. It just generates extra C++ code for you.)

Solution 3 - C++

I don't consider it unreasonable that Qt requires a special pre-processing tool, considering how large and comprehensive of a library it is.

Other similarly comprehensive libraries such as Boost and GLib don't require special pre-processing tools but do make extensive use of the standard C preprocessor. Qt could have been implemented using only the C preprocessor, but by using its own special preprocessing tool, it can provide a cleaner syntax and avoid many of the pitfalls associated with C preprocessor macros.

As has been answered already, though, you can use Qt without moc, just not anything that requires signals and slots. Yes, this does include all of the GUI stuff, but Qt is not by any means just a GUI library.

Solution 4 - C++

Using Qt while avoiding moc will be more difficult than just using them together as intended. You will also sacrifice most of the interesting features that motivated others to recommend Qt.

Without moc you can't

  • Use signals & slots (which are all but required for UI)
  • Use the dynamic property system (needed to write plugins, among other things)
  • Use the internationalization features
  • Expect to get help from anybody when nothing works

If you want to use Qt, use moc. In fact, don't even worry about moc -- just use QMake. You can write a QMake .pro file that looks like this:

TARGET = myApp

FORMS += MainWindow.ui

HEADERS += MainWindow.h

SOURCES += MainWindow.cpp
SOURCES += main.cpp

Everything will be taken care of automatically. Or you can spend all your time trying to figure out how to avoid moc.

See https://doc.qt.io/archives/qt-4.7/metaobjects.html and https://doc.qt.io/archives/qt-4.7/moc.html#moc

Solution 5 - C++

I don't have a full answer, but as I understand it, moc mainly (or perhaps only) generates additional C++ code. So potentially there's nothing it does that you couldn't also do yourself manually. However, I have no idea how tedious that might be nor how much study it might take to understand all the necessary concepts and details that go into that code.


Also, as I side note: In my opinion, the reason you're getting as much defense of Qt and moc is because you started your question with the strongly worded "I think it's unreasonable" which is easily interpreted to mean that you don't think moc should ever have existed. This distracts from your actual question. I think it would have been better just to say "moc doesn't fit into my build system" or simply "I have my own reasons for not wanting to use it".

Solution 6 - C++

I really can't think of anything so unique and useful with Qt without using QObjects. I wish they worked their way around that pre-compilation step.

Solution 7 - C++

Is it possible? As long as you're not doing any gui programming, probably. Personally I mostly run with PyQt these days, so it's not a big concern for me.

Why you shouldn't care: Given the nature of the "precompilation" if you're using cmake or qmake, it's not really a big deal in terms of inconvenience. If you're doing anything with a GUI these days, you should be using a graphical designer for most of the work anyway, so you're already adding some "pre-compilation" steps.

Regarding why they did it: You might be interested to read Qt's explanation: http://doc.qt.io/qt-4.8/templates.html

It boils down to:

  • The template solution lacks properties and overloading
  • The moc solution prevents signals from breaking binary compatability
  • Runtime analysis and modification are possible with the non-templated signals/slots mechanism

On a side note, multithreading signals/slots are also an advantage of their system.

Solution 8 - C++

You can use Qt without the moc, but then you lose certain functions, especially those that make Qt interesting in the first place (such as most of the GUI stuff, signals and slots, and string translation). But it's still a nice general purpose library, even without moc.

Solution 9 - C++

I have a solution, that is not super-clean and not 100% satisfactory, but that allows to connect Qt signals to your own code without having to use the MOC compiler (I had exactly the same constraint as in the question, i.e. not able to run the MOC compiler in the building process of my application).

To be able to capture Qt signals without using MOC, I am using the following tricks:

(1) get the definition of QMetaCallEvent (copy it from ): In Qt 5.x, you will have something like:

class QMetaCallEvent : public QEvent {
public:
    inline int id() const {
        return method_offset_ + method_relative_;
    }
    
    virtual void placeMetaCall(QObject *object);

private:
    QMetaCallEvent();
    void* slotObj_;
    const QObject *sender_;
    int signalId_;
    int nargs_;
    int *types_;
    void **args_;
    void *semaphore_;
    void *callFunction_;
    ushort method_offset_;
    ushort method_relative_;
};

(2) In your widget class that needs to capture Qt signals, you will inherit from a Qt widget (say QButton), and define the following function:

// Inspired by QObject::connect() in src/corelib/kernel/qobject.cpp
bool connect_sender(
    const QObject* sender, const char* signal, int method_index
) {

        // We need to generate MetaCall events (since QObject::event()
        //   is the only virtual function we can overload)
        // (note that the other connection types do not generate events).
        Qt::ConnectionType type = Qt::QueuedConnection ;

        if(sender == 0 || signal == 0) {
            std::cerr << "null sender or signal" << std::endl ;
            return false ;
        }

        QByteArray tmp_signal_name;
        const QMetaObject *smeta = sender->metaObject();
        ++signal; //skip code
        int signal_index = smeta->indexOfSignal(signal);
        if (signal_index < 0) {
            // check for normalized signatures
            tmp_signal_name = 
                QMetaObject::normalizedSignature(signal).prepend(*(signal - 1));
            signal = tmp_signal_name.constData() + 1;
            signal_index = smeta->indexOfSignal(signal);
            if (signal_index < 0) {
                std::cerr << "Signal \'" << signal << "\' not found" 
                          << std::endl ;
                return false;
            }
        }

        int *types = 0;

        QMetaObject::connect(
            sender, signal_index, this, method_index, type, types
        ) ;

        return true ;
    }

(3) overload the event() function:

bool event(QEvent* e) {
    if(e->type() == QEvent::MetaCall) {
        QMetaCallEvent* ev = static_cast<QMetaCallEvent*>(e);
        switch(ev->id()) {
            // insert your handling code here
        }  
        return true;
    }
    return QObject::event(e) ;
}

Now, if you call connect_sender(qobject, signal_name, method_index), this will call event() each time the signal is fired, with the specified method_index retrieved in ev->id().

Important note: I have been using this trick in my application for several years, it works quite well, but it is not very clean. One of the consequences is that whenever the definition of QMetaCallEvent changes, you need to edit your declaration accordingly (unfortunately it is not exposed in the header files of Qt).

Solution 10 - C++

I'm currently in the position of needing to find alternatives to MOC. So far I use GLib for text translation and I'm in the middle of reengineering a signals/slots library I found on the web (sigslot) using C++ templates and C macros combined. The boring and exhausting part is redoing the GUI for my app and replacing normal Qt widgets with my own widgets (i.e. QPushButton -> MyPushButton) through widget promotion (a feature of Qt Designer). This way I can have my widgets emit templated signals instead of Qt's. There's a catch, tho. My "modified" widget classes MUST be run through the preprocessor, but that's a once-in-a-lifetime step. After that, I can move on.

I can afford to do all of this only because I have already written an Application Framework library with its own event loop (well, it's a wrapper that piggybacks on Qt's event loop code), multithreading and string classes, etc. My project will only need Qt to display the nice and nifty widgets.

But if you don't have these tools at your disposal - which I'm sure you don't - trust me, trying to get rid of Qt's preprocessor is going to be a royal pain in the arse.

Here's my message to you: If you can use QMake or moc, just use them.

Solution 11 - C++

If you just need to connect to signals coming from Qt objects, a hack solution is to utilize existing QT objects that have public or protected virtual slots that match the signature of the signal you want to connect to. You can subclass the QT object and re-implement the virtual slot as a proxy to perform whatever action you need to when the QT signal is emitted. E.g.,

class SignalProxy : public QWidget
{
public:
  SignalProxy() {}
  
  void setVisible( bool isVisible )
  {
     // Do whatever you want to do when the signal is emitted.
  }
};
     

// code to connect the signal, e.g., to a QWebView object
SignalProxy proxy;
QWebView webview;
QObject::connect( &webview, SIGNAL(loadFinished(bool)),
        &proxy, SLOT(setVisible(bool)) );

It's not pretty but it gets the job done. If you were really intent on doing without the MOC you could probably locate existing Qt objects to use as proxies for just about any signal signature you need, e.g., the QAbstract... classes have lots of virtual slots, and you could hide all that nastiness in a library that provides a boost signals or tr1::function<> style API for connecting to QT signals.

Calling slots on QT objects is less of a concern than receiving signals, since you can generally invoke the slot method directly.

Solution 12 - C++

(sorry for reviving such an old post)

I was required to do a C/W assignment for my MSc unit in 3D Software Development.

Unfortunately a requirement was to use Qt to provide an OpenGL context rather than use Glut, native X11, Gtk etc...

I did not want to use MOC and with a lot of fiddling I was able to get just enough callbacks (such as keyboard, mouse, paint, timer etc...) to make a usable submission. So for using Qt with a primary reason for OpenGL software, it actually works fine without MOC.

However, I can't see how a full application could be developed without using MOC. Which is a shame.

This Qt MOC thing is a pain. I don't understand why so many C++ developers seem to find it acceptable frankly. It is extremely unportable and will get crusty fast! (Just try to get some Borland Kylix C++ code to compile. You will soon realize what a bad idea this is).

If I wanted to use non-standard C++, I would just use Microsoft C++/CLI.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionBilly ONealView Question on Stackoverflow
Solution 1 - C++Dr. SnoopyView Answer on Stackoverflow
Solution 2 - C++patstewView Answer on Stackoverflow
Solution 3 - C++Tyler McHenryView Answer on Stackoverflow
Solution 4 - C++Steve SView Answer on Stackoverflow
Solution 5 - C++TheUndeadFishView Answer on Stackoverflow
Solution 6 - C++SundarView Answer on Stackoverflow
Solution 7 - C++jkerianView Answer on Stackoverflow
Solution 8 - C++Sebastian NegraszusView Answer on Stackoverflow
Solution 9 - C++BrunoLevyView Answer on Stackoverflow
Solution 10 - C++RickView Answer on Stackoverflow
Solution 11 - C++Matt PlacekView Answer on Stackoverflow
Solution 12 - C++Karsten PedersenView Answer on Stackoverflow