Russian Qt Forum
Ноябрь 25, 2024, 04:56 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 [2]   Вниз
  Печать  
Автор Тема: Связать число со слотом.  (Прочитано 14519 раз)
Eugene Efremov
Гость
« Ответ #15 : Сентябрь 04, 2008, 09:49 »

Я не считаю switch/case наилучшим во всех случаях, но в ряде случаев применение этой конструкции вполне оправдано. В частности для исходного примера с enum MyEnum {Foo, Bar, Baz ....}; т.е. тогда когда "некая величина" принимает конечное, заранее известное, и, желательно небольшое количество значений.

У этой конструкции есть очень нехорошее свойство: появившись в одной точке программы оно стремится расползтись и продублировать себя везде, где только можно. За примерами далеко ходить не надо: возьмем, к примеру,  QAbstractItemModel и посчитаем все методы в которых фигурирует role. Тривиальные реализации этих методов потребуют, скорее всего, вложенного switch/case: для role и для индекса. Одинакового для них для всех.

Так что, если его использовать, надо принять меры, чтобы само перечисление не вылезло за пределы того метода, где оно используется. Иначе рано или поздно придется применить эту конструкцию во второй раз. И в третий. И в четвертый. А это — дублирование кода, со всеми вытекающими...

Ну и еще его, конечно, можно использовать при автоматической генерации кода. Роботу дублирование не страшно...

Т.е. было бы оптимальней хранить в хэше не сигнатуру сигнала/слота (в обшем случае метода), а индекс метода (QMetaObject::indexOfMethod()) и вызывать qt_metacall() напрямую, вот только qt_metacall() не документирован у троллей, и вполне могут чтото поменят в будущем. Грустный

Мда. Поиграл с этим, получилось примерно вот что:

Код:
class Caller : public QObject
{
Q_OBJECT

private:
QHash<int, int> ftrs;

protected:
bool add(int i, const char *slot) // use: add(i, SLOT(foo()))
{
int id = metaObject()->indexOfMethod(QMetaObject::normalizedSignature(slot+1));
if(id == -1) return false;
ftrs[i] =  id;
return true;
}

virtual void defMethod() {}

public:
Caller(QObject *p = 0): QObject(p) {}

bool call(int i)
{
if(ftrs.contains(i))
{
qt_metacall(QMetaObject::InvokeMetaMethod, ftrs[i], 0);
return true;
}
defMethod();
return false;
}

};
И это еще без передачи аргументов. Под 4.4.1 работает. Будет ли работать под другими версиями?...

P.S. Я тут на неделю уезжаю, так что с дискуссией пока придется завязать...
Записан
ритт
Гость
« Ответ #16 : Сентябрь 04, 2008, 10:40 »

работать будет, но чисто теоритически индекс метода у суперкласса может отличаться от индекса того же метода у наследника. вдобавок у суперкласса может вообще не оказаться метода под таким индексом, а у другого наследника под тем же индексом будет совершенно другой метод
тогда придётся везде расставлять дополнительные проверки или работать только с суперклассами

как уже обсуждалось в другом треде, вызов метода по сигнатуре всего лишь в 10 раз медленнее прямого вызова, что сущие пустяки в масштабе программы
Записан
Alex03
Гость
« Ответ #17 : Сентябрь 04, 2008, 11:51 »

Т.е. было бы оптимальней хранить в хэше не сигнатуру сигнала/слота (в обшем случае метода), а индекс метода (QMetaObject::indexOfMethod()) и вызывать qt_metacall() напрямую, вот только qt_metacall() не документирован у троллей, и вполне могут чтото поменят в будущем. Грустный

Мда. Поиграл с этим, получилось примерно вот что:
...
Можно расширить для вызова членов других объектов, например в хэше хранить структурку с указателем на объект и индексом метода этого объекта. Но тут надо гарантировать то, что объект не будет уничтожен пока ссылка на него имеется в хэше, ну или отлавливать QObject::destroyed() этих объектов (или в конце концов просто QPointer задействовать).
Второй вариант расширения функциональности - Хранить в хэше не структурку, а QList со структурками, дабы на одно "некое значение" можно было "коннектить" несколько сигналов/слотов.
После этих изменений Caller (иль например SlotMapper) можно использовать везде где угодно как член класса.

Цитировать
И это еще без передачи аргументов.
А какие тут аргументы имеются ввиду? Чтото у меня реальных примеров не придумывается...

Цитировать
Под 4.4.1 работает. Будет ли работать под другими версиями?...
Думаю под всеми 4.х.х должно работать.

Константин Так как индекс задаётся не статически, а получается из сигнатуры с помощью metaObject()->indexOfMethod() то всё ОК.
Собственно connect() также получает индексы сендера и ресивера по сигнатуре и запоминаются именно индексы. А уже activate() по индексу сигнала находит все ресиверы с соотв. индексами и вызывает их прямо или через очередь.
Записан
Alex03
Гость
« Ответ #18 : Сентябрь 04, 2008, 12:00 »

Странно что тролли хранят сигнатуры а не хэши сигнатур, их то можно было бы MOC-ом сгенерить
QMetaObject::indexOfХХХХХ() отрабатывали бы куда быстрее...
А следовательно и connect() и invokeMethod() работали бы быстрее...
Записан
pastor
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 2901



Просмотр профиля WWW
« Ответ #19 : Сентябрь 04, 2008, 12:03 »

Странно что тролли хранят сигнатуры а не хэши сигнатур, их то можно было бы MOC-ом сгенерить
QMetaObject::indexOfХХХХХ() отрабатывали бы куда быстрее...
А следовательно и connect() и invokeMethod() работали бы быстрее...


имхо этими мыслями можно поделиться с тролями.Накатай suggestion им
Записан

Integrated Computer Solutions, Inc. (ICS)
http://www.ics.com/
ритт
Гость
« Ответ #20 : Сентябрь 04, 2008, 12:16 »

Так как индекс задаётся не статически, а получается из сигнатуры с помощью metaObject()->indexOfMethod() то всё ОК.
Собственно connect() также получает индексы сендера и ресивера по сигнатуре и запоминаются именно индексы. А уже activate() по индексу сигнала находит все ресиверы с соотв. индексами и вызывает их прямо или через очередь.

тогда придётся хранить индекс и указатель на объект (либо метаобъект)
коннекту позволительно оперировать с индексами - он уже все проверки сигнатур выполнил, указатель на объект имеет...а мок всё-равно понагенерил кода с использованием индексов...
Записан
Alex03
Гость
« Ответ #21 : Сентябрь 04, 2008, 12:32 »

тогда придётся хранить индекс и указатель на объект
Про то и речь, с сигнатурой тоже указатель на объект нужен...
Записан
ритт
Гость
« Ответ #22 : Сентябрь 04, 2008, 13:47 »

уточню свою мысль:
чтобы узнать индекс метода, нужен указатель на объект (или метаобъект, или хардкодить на статический метаобъект класса) - лишь после этого можно утверждать, что индекс валиден;
в ситуации с сигнатурой указатель на объект потребуется лишь в момент получения индекса метода по сигнатуре и коннекте/вызове метода, а саму сигнатуру можно получать от третьей стороны динамически (скажем, из плагина или из текстового файла - без примеров, просто абстракция), что нереализуемо на индексах (не будет гарантии работоспосоности при изменениях)

в случае с индексами всё-равно придётся получать сигнатуру (проверять по ней параметры, делать инвок, коннект и т.д.) и валиден индекс будет ровно до первого изменения указателя на объект (затем валидность не гарантируется и нужно выполнять проверки снова)
в случае с сигнатурами индекс потребуется только для работы с метаметодом - так что, сигнатуру можно сразу использовать при вызове коннект/инвок /* только желательно бы сигнатуру нормализовать сразу при получении */
в итоге можно ничего не хардкодить и смело строить дерево действий, зависящих от значения переменной (тема треда), хоть из текстового файла, а скорость отработки будет выше

мне не так давно пришлось любиться с системой метаобъектов...вышесказанное - всего лишь теория, подтверждённая практикой Улыбающийся
Записан
Alex03
Гость
« Ответ #23 : Сентябрь 05, 2008, 05:43 »

Константин Вроде про динамическое изменение указателей на объект для одной и той же сигнатуры речь не шла.
Впрочем ничто не мешает получить индекс при каждом изменении указателя. Ведь в большинстве случаем количество изменений(установок) указателя намного меньше количества вызовов слота/сигнала.
Записан
ритт
Гость
« Ответ #24 : Сентябрь 05, 2008, 10:45 »

Впрочем ничто не мешает получить индекс при каждом изменении указателя. Ведь в большинстве случаем количество изменений(установок) указателя намного меньше количества вызовов слота/сигнала.
ну, а что потом будем делать с этим индексом? Улыбающийся
в инвок индекс на запихать - всё-равно потребуется брать сигнатуру - и в чём тогда смысл хранения индексов?
Записан
ритт
Гость
« Ответ #25 : Сентябрь 05, 2008, 11:05 »

кстати, в 4.5.0 был перегруженный инвок, принимающий индекс метода, но вчера весь этот код искоренили - наверное, на то есть причины
Записан
Alex03
Гость
« Ответ #26 : Сентябрь 07, 2008, 12:17 »

кстати, в 4.5.0 был перегруженный инвок, принимающий индекс метода, но вчера весь этот код искоренили - наверное, на то есть причины
А qt_metacall() случайно не документировали?

С другой стороны понятно, что пока внутренности реализации сигналов/слотов "спрятаны" троли оставляют за собой право менять там что угодно.
Записан
ритт
Гость
« Ответ #27 : Сентябрь 07, 2008, 15:28 »

А qt_metacall() случайно не документировали?

есть несколько строк комментов в коде Улыбающийся
плюсом добавили internal-only статический qt_metacall(), который использует новый механизм "метаконструктор" для создания экземпляра и вызова метода...но это скорее больше скриптам полезно, чем данной теме Улыбающийся
Записан
Страниц: 1 [2]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.13 секунд. Запросов: 22.