Den 26-10-2012 11:45, d3fault skrev:
> tl;dr: How can I use the Q_OBJECT macro within a pre-processor macro?
>
> So I've got the rewrite 99% done, and I mean it looks a heck of a lot
> cleaner than the first example. Fixed a lot of typos in comments too.
>
> That 1% is proving to be a problem though :(.
>
> If I don't use that "template" idea I was talking about, then it works
> easy. The thing is, I don't want to ever have to sub-class QThread.
> Why? Simple: Business logic does not belong in a QThread sub-class. I
> want it to be re-usable to the point where I don't have to sub-class
> QThread for every object type.
>
> So nao I'm asking for halp.
>
> Templates and MOC don't play nice together. The only hacky workaround
> I got working with templates/moc required me to sub-class a templated
> class, guh. Might as well sub-class QThread.
>
> I tried with a pre-processor macro, but the Q_OBJECT macro within my
> macro messes things up :(.
>
> The only problem I'm having is one of string substitution, lmfao.
>
> Here's what my non-working macro currently looks like:
>
> #define DECLARE_INTENT_TO_USE_OBJECT_ON_THREAD(UserObjectType) \
>       class UserObjectType##OnThreadHelper : public QThread \
>       { \
>               Q_OBJECT \
>       public: \
>               explicit UserObjectType##OnThreadHelper(QObject *parent = 0) :
> QThread(parent) { } \
>       protected:
>               virtual void run() \
>               { \
>                       UserObjectType qobj; \
>                       emit 
> object##UserObjectType##IsReadyForConnectionsOnly(&qobj); \
>                       exec(); \
>               } \
>       signals: \
>               void object##UserObjectType##IsReadyForConnectionsOnly(&qobj); \
>       };
>
>
> ^^^I hope the formatting doesn't mess up when I post this. I am
> escaping all the newlines properly.
>
> Use:
>
> In your header, after #include'ing both the macro and the QObject
> inherited types you want to work with on backend threads, you do:
> DECLARE_INTENT_TO_USE_OBJECT_ON_THREAD(SimpleBackend1)
> DECLARE_INTENT_TO_USE_OBJECT_ON_THREAD(SimpleBackend2)
> //etc. Way easier than overriding QThread::run() for each type...
>
> Which creates the classes that you then add to your class as members
> (the one that "hasA" QThread/backend-object... in my example: the
> "test" class):
>
> private:
>       SimpleBackend1OnThreadHelper m_Backend1ThreadHelper;
>       SimpleBackend2OnThreadHelper m_Backend2ThreadHelper;
>
>
> then connect and start:
>
> //in my "test" class's constructor
> connect(&m_Backend1ThreadHelper,
> SIGNAL(objectSimpleBackend1IsReadyForConnectionsOnly(SimpleBackend1*)),
> this, SLOT(handleSimpleBackend1ReadyForConnectionsOnly(SimpleBackend1*)));
> m_Backend1ThreadHelper.start();
> connect(&m_Backend2ThreadHelper,
> SIGNAL(objectSimpleBackend2IsReadyForConnectionsOnly(SimpleBackend2*)),
> this, SLOT(handleSimpleBackend2ReadyForConnectionsOnly(SimpleBackend2*)));
> m_Backend2ThreadHelper.start();
>
>
> and to stop:
> //handleAboutToQuit or similar
> m_Backend1ThreadHelper.quit();
> m_Backend2ThreadHelper.quit();
> m_Backend1ThreadHelper.wait();
> m_Backend2ThreadHelper.wait();
>
>
> ...which causes the object of the type that you pass into the macro to
> go out of scope after exec() returns. Qt's signals/slots handles the
> object's disappearance with no problem (signals/slots are smart,
> woot).
>
>
>
> But that's the thing: the macro doesn't work because of the Q_OBJECT
> macro within it. I also tried Q_##OBJECT to try to get it to evaluate
> twice... except that doesn't work because MOC runs before the
> preprocessor does.
>
> I could trivially add a build step that does string replacing, but
> then it isn't very portable/re-usable :(.
>
>
> Would be nice to be able to do clean threading with just:
>
> #include "objectonthreadhelper.h" //the macro
> DECLARE_INTENT_TO_USE_OBJECT_ON_THREAD(MyCustomObjectType)
> MyCustomObjectTypeThreadHelper m_MyCustomObjectTypeThreadHelper;
> connect(&m_Backend2ThreadHelper,
> SIGNAL(objectMyCustomObjectTypeIsReadyForConnectionsOnly(MyCustomObjectType*)),
> this, 
> SLOT(handleMyCustomObjectTypeReadyForConnectionsOnly(MyCustomObjectType*)));
> m_MyCustomObjectTypeThreadHelper.start();
>
>
> No more .moveToThread()... which doesn't let your object's constructor
> run on the thread
> No more overriding QThread::run()... business logic does not belong in
> there... and I don't want to do copy/paste programming for every
> object type I want on a backend thread
>
>
> Anyone have a portable solution to that string substitution problem?

Have you tried a double base class solution to this?

class WorkerThreadBase : public QObject {
   Q_OBJECT

signals: ...
slots: ...
};

template <typename T> class WorkerThread : public WorkerThreadBase {
   // No Q_OBJECT
...
};

This is a common pattern when you need a class that's template based but 
at the same time isn't. Polymorphism of template classes can be done 
this way, for example.

Bo Thorsen.

Come by my DevDays talk in Berlin - "Designing for testability". Learn how to 
build and run your unit tests with the Qt application.

Fionia Software - Qt experts for hire.

_______________________________________________
Interest mailing list
[email protected]
http://lists.qt-project.org/mailman/listinfo/interest

Reply via email to