PDA

View Full Version : templates and Q_OBJECT



TheKedge
13th September 2006, 17:19
hello everyone,
I get the error:
.\Logger.h(20): Error: Template classes not supported by Q_OBJECT
when I have the following ...



template<typename T>

class Logger : public QThread
{
Q_OBJECT

public:
Logger( T* fridge){}
virtual ~Logger();
...



What can I do?
I want to pass an instance of any class (provided that the class has a function x()) to the constructor of Logger, so that the Logger can call the func. Is that possible?

thanks
K

jacek
13th September 2006, 17:27
I want to pass an instance of any class (provided that the class has a function x()) to the constructor of Logger, so that the Logger can call the func. Is that possible?
Of course it is. That's what interfaces are for.


class MonitoredObject
{
public:
virtual QString status() = 0;
};

class Fridge : public SomeClass, public MonitoredObject
{
...
QString status() { if( rand() % 2 ) return "OK"; else return "ON FIRE"; }
...
};

TheKedge
14th September 2006, 11:13
ok, but I'm not sure if that's what I want. I was thinking of something like


logger::logger (<T*> thingToLog):thing(thingToLog)
{
<T*> thing;
}
logger::doJob()
{
thing->logData();
}


and the object which wants logging to be done makes an instance of a logger thus:


{
logger = new logger(this);

and provides a func which decides what and how to log things


logData()
{
logger->log(getOneDatum());
logger->log(getAnotherDatum());
logger->flush();
}

My logger class has a fairly big interface which doesn't really have much to do with the class being logged. I just thought that that might be a good way of doing things since I don't inherit any interface - is it a bad idea? is it a question of having friends or having inheritance? what do you recommend?
thanks for the help
Kev

TheKedge
14th September 2006, 11:19
ahh, one more thing:
when I try:


class Refrigerator : public BaseDevice, public Logger

thus inheriting the logger

I get a error on trying to connect things:



connect(view, SIGNAL(elementClicked(int /*index*/, int /*state*/)), fridge, SLOT(setSwitch(int /*index*/, int /*state*/)));

My logger is

class Logger : public QThread

and the error is can't uniquely convert from class Refrigerator * to const class QObject *

Will I have to restructure Logger before inheriting it?

K

jacek
14th September 2006, 14:06
when I try:
class Refrigerator : public BaseDevice, public Logger
thus inheriting the logger

I get a error on trying to connect things
This is a Qt limitation. The class that inherits QObject must be first:


class Refrigerator : public Logger, public BaseDevice



connect(view, SIGNAL(elementClicked(int /*index*/, int /*state*/)), fridge, SLOT(setSwitch(int /*index*/, int /*state*/)));
I'm not sure if Qt will like those comments.

TheKedge
14th September 2006, 14:18
ok, but my BaseDevice is also a QObject ..

class BaseDevice : public QThread, public CommPort
where CommPort is not a Qt-based class

(Qt is fine with the comments, they just expand in the macro as comments)

is the template solution (my original scheme) also a limited by Qt?
i.e. Template classes not supported by Q_OBJECT


#include <QtCore>
template<class T>

class thing
{
Q_OBJECT
public:
thing( T* fridge):m_fridge(fridge) { }
virtual ~thing() { }

private:
T* m_fridge;

};

jacek
14th September 2006, 14:31
My logger class has a fairly big interface which doesn't really have much to do with the class being logged. I just thought that that might be a good way of doing things since I don't inherit any interface - is it a bad idea? is it a question of having friends or having inheritance? what do you recommend?
First of all you create a separate thread for each device. If there is a lot of such devices, you will loose a lot of time for context switching. Maybe it will be better if a single logger thread would serve more than one device?

The easiest way is to use an interface, but this requires a small change in all classes that need logging --- you must add another base class. The good news is that you will be able to treat all kinds of devices the same way and for example create a list of pointers that you can traverse and collect data (just be careful when you delete/remove someting).

Another solution is to stick with templates, but the problem is that Qt doesn't handle them. One way is to split the implementation into two classes.


class BaseLogger
{
public:
virtual void logData() = 0;
};

template< class T >
class Logger : public BaseLogger
{
public:
Logger( T* device );
void logData();
...
};

class LoggerThread : public QThread
{
Q_OBJECT
public:
// user will have to create Logger himself
LoggerThread( BaseLogger * );

// or like this, but I'm not sure if Qt will like it:
template< class T >
static LoggerThread * createLoggerFor( T* device );

void run()
{
if( logger != 0 ) {
logger->logData();
}
}
...
};After small modifications single logger thread will be able to handle multiple devices, but IMO the interface approach is cleaner.

jacek
14th September 2006, 14:40
ok, but my BaseDevice is also a QObject ..

class BaseDevice : public QThread, public CommPort
where CommPort is not a Qt-based class
Qt doesn't use virtual inheritance, so you would end with an object that represents two distinct threads at the same time. Only one of the base classes can be derived from QObject.


Qt is fine with the comments, they just expand in the macro as comments
The question is whether Qt will be able to remove them later when it comes to signature normalization during connection setup.


is the template solution (my original scheme) also a limited by Qt?
i.e. Template classes not supported by Q_OBJECT
Yes, moc can't generate code for template classes, since they require special treatment.

TheKedge
14th September 2006, 14:47
Jacek,
they are great answers!
thanks for the info, especially on Q_OBJECT and threads; I'll put your knowledge to my good use! thanks,
K

sunil.thaha
14th September 2006, 15:26
FYI


http://doc.trolltech.com/qq/qq15-academic.html
http://doc.trolltech.com/4.1/templates.html
http://www.handhelds.org/~zecke/apidocs/qt/moc.html

sunil.thaha
14th September 2006, 15:45
@jacek



template< class T > static LoggerThread * createLoggerFor( T* device );


could u please expain what that fn will do ?

assuming


template< class T >
class LoggerThread : public QThread {

jacek
14th September 2006, 16:01
could u please expain what that fn will do ?

assuming [...]
I don't know what it should do with your assumption, but my idea was not to make LoggerThread a template.

Compare this two:

LoggerThread *thread = new LoggerThread( new Logger< Fridge >( fridge ) );
LoggerThread *thread = LoggerThread::createLoggerFor< Fridge >( fridge );
In the second example user doesn't have to know anything about the Logger class and yes, your source code is 1 byte shorter ;)

sunil.thaha
15th September 2006, 06:41
My assumption was wrong.

did not notice the static function :mad: