Russian Qt Forum

Qt => Общие вопросы => Тема начата: bigirbis от Август 28, 2007, 10:26



Название: Q_OBJECT-грабли в Qt4.3
Отправлено: bigirbis от Август 28, 2007, 10:26
В Qt4.3 стало обязательным объявления макроса Q_OBJECT в классе, для того, чтобы можно было использование приведение qobject_cast <>. Но при этом не разрешается использование данного макроса в шаблонных классах. А код уже написан и работает... :(.

Есть какие-нибудь красивые методы выхода из данной ситуации?


Название: Re: Q_OBJECT-грабли в Qt4.3
Отправлено: Dodge от Август 28, 2007, 15:29
Эти "Грабли" выросли из нового механизма генерации метаданных, и на мой это взгляд очень даже ничего система, ноги у нее растут скорей всего от QtScript, так что решайте задачу иным способом.
Насчет шаблонов выхода нет, т.к. Q_OBJECT макрос для мок, а моку глубоко плевать на шаблоны, он их не понимает.
И по подробнее про qobject_cast, в чем проблема?... лучше кусок кода.



Название: Re: Q_OBJECT-грабли в Qt4.3
Отправлено: bigirbis от Август 28, 2007, 15:38
Вот небольшой пример. Это достаточно неплохо сокращает код и делает его более понятным.
Код:
template <class ObjT, class Parm1T, class RetT = void>
class ThreadRun : public QThread
{
public:
ThreadRun(ObjT *object, RetT (ObjT::*function)(Parm1T), Parm1T parm ,QObject *parent = NULL )
: QThread(parent), object_(object), function_(function), parm_(parm){}
~ThreadRun(){if(isRunning())this->wait();}
void run(){retval_ = (object_->*function_)(parm_);}
RetT & retval() {return retval_;}
void msleep( unsigned long msecs ) {QThread::msleep( msecs ); }
private:
ObjT *object_;
RetT (ObjT::*function_)(Parm1T);
Parm1T parm_;
RetT retval_;
};

Код:
ThreadRun < MyWidget, QString, QString > * s_s_Thread = qobject_cast < ThreadRun < MyWidget, QString, QString > * > ( sender() );


Название: Re: Q_OBJECT-грабли в Qt4.3
Отправлено: Dodge от Август 28, 2007, 15:45
...
Интересное решение, я об этом не подумал...

З.Ы. Еще можно попробовать сделать прототип, либо через макросы, получится "псевдо шаблон"  :D


Название: Re: Q_OBJECT-грабли в Qt4.3
Отправлено: vaprele07 от Август 28, 2007, 16:03
а что мешает пользоваться static_cast? мне например qobject_cast не нравится из за strcmp:
Код:
void *XButtonPrototype::qt_metacast(const char *_clname)
{
    if (!_clname) return 0;
    if (!strcmp(_clname, qt_meta_stringdata_XButtonPrototype))
return static_cast<void*>(const_cast< XButtonPrototype*>(this));
    if (!strcmp(_clname, "QScriptable"))
return static_cast< QScriptable*>(const_cast< XButtonPrototype*>(this));
    return QObject::qt_metacast(_clname);
}
в итоге все равно приводится через стандартный каст хотя см QT_NO_MEMBER_TEMPLATES!

Код:
template <class T>
inline T qobject_cast(const QObject *object)
{
#if !defined(QT_NO_MEMBER_TEMPLATES) && !defined(QT_NO_QOBJECT_CHECK)
    reinterpret_cast<T>(0)->qt_check_for_QOBJECT_macro(*reinterpret_cast<T>(object));
#endif
    return static_cast<T>(const_cast<const QObject *>(reinterpret_cast<T>(0)->staticMetaObject.cast(const_cast<QObject *>(object))));
}


Название: Re: Q_OBJECT-грабли в Qt4.3
Отправлено: Tonal от Август 29, 2007, 07:24
Вполне можно разделить поток и замыкание.
Код:
struct GenericClosure {
  void run() = 0
};
template <class ObjT, class Parm1T, class RetT = void>
struct ConcretClosure : GenericClosure {
  ConcretFunc(ObjT *object, RetT (ObjT::*function)(Parm1T), Parm1T parm):
    object_(object), function_(function), parm_(parm){}
  void run() {object_->*function_)(parm_);}
  RetT & retval() {return retval_;}
  private:
    ObjT *object_;
    RetT (ObjT::*function_)(Parm1T);
    Parm1T parm_;
    RetT retval_;
};

class ThreadRun : public QThread
{
public:
  ThreadRun(GenericClosure* closure, *parent = NULL )
    : QThread(parent), closure_(closure) {}
  ~ThreadRun(){if(isRunning())this->wait();}
  void run() {closure_->run();}
  GenericClosure* closure() {return closure_;}
  void msleep( unsigned long msecs ) {QThread::msleep( msecs ); }
private:
  GenericClosure* closure_;
};
Ну и приводить или через dynamic_cast (стандартный rtti) или static_cast, если типы тебе известны.
Например, в твоём примере
Код:
ThreadRun < MyWidget, QString, QString > * s_s_Thread = 
  qobject_cast < ThreadRun < MyWidget, QString, QString > * > ( sender() );
qobject_cast заменяется на static_cast и по смыслу и по действию. ;)
А если ты хочешь оставить проверку, которую он предоставляет, можно так:
Код:
assert(dynamic_cast<ThreadRun < MyWidget, QString, QString > *>(sender()));
ThreadRun < MyWidget, QString, QString > * s_s_Thread =
  static_cast < ThreadRun < MyWidget, QString, QString > * > ( sender() );