Вроде была уже тут такая тема, но я не смог найти, и к чему там пришли, тоже подзабыл
Так что побаяню
Почему сюда — потому что интересуют не абстрактные архитектуры, а плюсовые решения.
Я как-то отстал от жизни, привык один патерн использовать, меня в принципе устраивает, но может, научная мысль уже далеко ушла вперед?
Вот есть некая очередь сообщений/событий. Из неё они извлекаются и как-то обрабатываются.
Мне известны буквально только пара механизмов для реализации такого поведения. Например:
1) Qt. Там из очереди сообщений они извлекаются, где-то в каком-то ассоциативном массиве ищется объект, который подписался на событие, и его слот, и этот слот вызывается, всякие кастинги доп. данных сообщений производятся на основе метаинформации, полученной при помощи метакомпилера. Как-то так вроде, да?
Пользоваться в принципе удобно, но напрягает необходимость препроцессора, и неэффективность данного метода (и не надо мне рассказывать, что на современных системах это копейки )
2) В разных книжках читал, но никогда не использовал — в очередь кладутся уже объекты, которые знают сами, что надо делать (с методом virtual doJob() etc). Никогда не понимал этого. Либо я саму идею не понял правильно, либо что-то еще, но место, где генерируется событие, обычно же ничего не знает о том, как событие должно обрабатывается. Никогда не пробовал применить такой способ.
3) Виндовая очередь оконных сообщений и её обработка. Тут есть вариации: чистый WinAPI со своими message crackers из windowsx.h, WTL со схожим механизмом, MFC. С MFC плотно дела не имел, там вроде немного по другому — уже есть некая "карта" обработки сообщений, которая дергает виртуальные методы, которые переопределяются в пользовательском коде. Из плюсов — отсутствие какого-либо оверхеда вообще. Да и использовать вполне удобно, когда все кракеры уже написаны до нас.
Я в основном привык к последнему "виндовому" подходу, раньше как-то работал с разными протоколами обмена с различными устройствами, и вполне успешно применял его для обработки различных поступающих данных. Но из недостатков у такого подхода в наличии имеется активное использование препроцессора, и прочие грязные штуки — кастинги всего во всё и прочее всё такое.
Вот хочу узнать, как подобное можно красиво именно на плюсах реализовать. Хотелось бы обойтись без головоломных шаблонов, но наверно не получится
M>1) Qt. Там из очереди сообщений они извлекаются, где-то в каком-то ассоциативном массиве ищется объект, который подписался на событие, и его слот, и этот слот вызывается, всякие кастинги доп. данных сообщений производятся на основе метаинформации, полученной при помощи метакомпилера. Как-то так вроде, да? M>Пользоваться в принципе удобно, но напрягает необходимость препроцессора, и неэффективность данного метода (и не надо мне рассказывать, что на современных системах это копейки )
ИМХО конечно, но все это совершенно неверно.
Механизм сигналов и слотов и работа Qt с сообщениями платформы это разные вещи.
Если коротко, то Qt получает события от платформы, некоторые обрабатывает только сама,
большинство превращает в наследников класса QEvent. Любой класс наследующий
от QObject или его детей, может переопределить виртуальный метод "bool QObject::event(QEvent *)"
и проверить QEvent::type и сделать "cast" в правильного наследника QEvent.
После этого он может сделать в принципе что угодно, может сделать "emit signal",
может послать другой QEvent другому объекту, ну или вообще вызывать метод другого объекта
напрямую. Можно также встроиться в систему с помощью "Qt event filter" и перехватывать
события предназначенные другому объекту.
Здравствуйте, Zhendos, Вы писали:
M>>1) Qt. Там из очереди сообщений они извлекаются, где-то в каком-то ассоциативном массиве ищется объект, который подписался на событие, и его слот, и этот слот вызывается, всякие кастинги доп. данных сообщений производятся на основе метаинформации, полученной при помощи метакомпилера. Как-то так вроде, да? M>>Пользоваться в принципе удобно, но напрягает необходимость препроцессора, и неэффективность данного метода (и не надо мне рассказывать, что на современных системах это копейки )
Z>ИМХО конечно, но все это совершенно неверно. Z>Механизм сигналов и слотов и работа Qt с сообщениями платформы это разные вещи.
Это разные вещи, да. Но я их и не смешивал. Qt всю работу с событиями от платформы преобразует в работу со своими сигналами-слотами. И я хочу обсудить именно это.
Z>Если коротко, то Qt получает события от платформы, некоторые обрабатывает только сама, Z>большинство превращает в наследников класса QEvent. Любой класс наследующий Z>от QObject или его детей, может переопределить виртуальный метод "bool QObject::event(QEvent *)"
Qt переваривает сообщения платформы и генерирует свои события, и дальше все идет только в рамках Qt. Я привел как пример именно Qt-шный способ обработки сообщений, вне зависимости, как они были изначально сгенерированы — будь то Win32, или XWindows или еще что-то
Z>и проверить QEvent::type и сделать "cast" в правильного наследника QEvent. Z>После этого он может сделать в принципе что угодно, может сделать "emit signal", Z>может послать другой QEvent другому объекту, ну или вообще вызывать метод другого объекта Z>напрямую. Можно также встроиться в систему с помощью "Qt event filter" и перехватывать Z>события предназначенные другому объекту.
Да, Qt оставляет возможность обрабатывать системно-зависимые события. И?
Здравствуйте, Marty, Вы писали:
M>Здравствуйте, Zhendos, Вы писали:
Z>>и проверить QEvent::type и сделать "cast" в правильного наследника QEvent. Z>>После этого он может сделать в принципе что угодно, может сделать "emit signal", Z>>может послать другой QEvent другому объекту, ну или вообще вызывать метод другого объекта Z>>напрямую. Можно также встроиться в систему с помощью "Qt event filter" и перехватывать Z>>события предназначенные другому объекту.
M>Да, Qt оставляет возможность обрабатывать системно-зависимые события. И?
Словосочетание "системно-зависимые" здесь лишнее.
Если я напишу что-нибудь типа
bool event(QEvent *e) override
{
if (e->type() == QEvent::MouseButtonPress)
}
или
void mousePressEvent(QMouseEvent *event) override
то этот код будет работать и на mac os, и на linux/x11, и на windows,
и даже на android устройстве без мышки.
Это системно независимый код. И именно так предполагается обрабатывать события.
Механизм сигналов/слотов использует event loop/event queue только в случаях
когда объект делающий "emit signal" и объект, который подключился к этому сигналу
в принадлежат разным потокам и использован QueuedConnection тип соединения.
Здравствуйте, Zhendos, Вы писали:
M>>Да, Qt оставляет возможность обрабатывать системно-зависимые события. И?
Z>Словосочетание "системно-зависимые" здесь лишнее.
Это не WM_KEYPRESS или WM_MOUSEMOVE. Это Qtшные события.
Z>то этот код будет работать и на mac os, и на linux/x11, и на windows, Z>и даже на android устройстве без мышки. Z>Это системно независимый код. И именно так предполагается обрабатывать события.
Ок.
Z>Механизм сигналов/слотов использует event loop/event queue только в случаях Z>когда объект делающий "emit signal" и объект, который подключился к этому сигналу Z>в принадлежат разным потокам и использован QueuedConnection тип соединения.
Приложение без потоков, кроме основного. event-loop'а нет?
В многопоточном приложении еще проще, да?
ЗЫ Чего вы все прикопались к моему вольному описанию системы Qt-шных событий? Я привел его только как один из известных мне вариантов организации взаимодействия изолированных друг от друга частей софтины, когда, например, клавиатура просто генерирует события нажатия клавиш, а в разном прикладном коде эти нажатия клавиш требуется обрабатывать по-разному.
Здравствуйте, Marty, Вы писали:
M>Здравствуйте, Zhendos, Вы писали:
M>>>Да, Qt оставляет возможность обрабатывать системно-зависимые события. И? Z>>Словосочетание "системно-зависимые" здесь лишнее. M>Не лишнее. M>Это не WM_KEYPRESS или WM_MOUSEMOVE. Это Qtшные события.
Вот именно. Qtшные события (QEvent и его дети) это системно независимые события.
В Qt конечно есть способ перехватывать и обрабатывать и WM_KEYPRESS/WM_MOUSEMOVE,
но для этого предназначен другой механизм, и он конечно как раз является
"системно-зависимым", то есть разный для разных ОС.
Z>>Механизм сигналов/слотов использует event loop/event queue только в случаях Z>>когда объект делающий "emit signal" и объект, который подключился к этому сигналу Z>>в принадлежат разным потокам и использован QueuedConnection тип соединения.
M>Приложение без потоков, кроме основного. event-loop'а нет?
Есть event loop, и может быть несколько, например при использовании модальных
диалогов, но механизм signal/slot в этом случае его вообще не использует.
Там просто вызов функций напрямую.
M>В многопоточном приложении еще проще, да?
Там сложнее как раз все.
M>ЗЫ Чего вы все прикопались к моему вольному описанию системы Qt-шных событий? Я привел его только как один из известных мне вариантов организации взаимодействия изолированных друг от друга частей софтины, когда, например, клавиатура просто генерирует события нажатия клавиш, а в разном прикладном коде эти нажатия клавиш требуется обрабатывать по-разному.
Потому что описание неверно совсем.
С одной стороны платформо-независимый механизм QEvent и QEventLoop и
платформо-зависимый зависимые механизмы никак не связаны с signal/slot.
С другой стороны в коде ниже,
при вызове
foo.emitSignal();
никакого поиска в ассоциативном массиве не будет,
для каждого сигнала есть его индекс для данного класса,
сначала по индексу мы получим список подключенных к данному сигналу "слушателей",
потому для каждого элемента списка просто вызовем аналог `std::function`,
если все объекты живут в том же потоке (или использован DirectionConnection флаг),
то emitSignal аналогично проходу по `std::list<std::function<>>` и вызову каждой
функции. То есть отличие от прямого вызова функции это только вложенность,
вместо прямого вызова лямбды будет вызов emitSignal, он вызовет QMetaObject::activate,
и потом уже лямбда (может еще пару промежуточных стадий до этого).
Z>>>Механизм сигналов/слотов использует event loop/event queue только в случаях Z>>>когда объект делающий "emit signal" и объект, который подключился к этому сигналу Z>>>в принадлежат разным потокам и использован QueuedConnection тип соединения.
Ну, я в общем не претендовал на доскональное знание кьютешных механизмов. Я спрашивал немного не об этом
M>2) В разных книжках читал, но никогда не использовал — в очередь кладутся уже объекты, которые знают сами, что надо делать (с методом virtual doJob() etc). Никогда не понимал этого. Либо я саму идею не понял правильно, либо что-то еще, но место, где генерируется событие, обычно же ничего не знает о том, как событие должно обрабатывается. Никогда не пробовал применить такой способ.
Патерн Наблюдатель?
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, Marty, Вы писали:
M>Да, Qt оставляет возможность обрабатывать системно-зависимые события. И?
Z>>Словосочетание "системно-зависимые" здесь лишнее.
M>Не лишнее.
Здравствуйте, Marty, Вы писали:
M>Здравствуйте, Zhendos, Вы писали:
Z>>>>Механизм сигналов/слотов использует event loop/event queue только в случаях Z>>>>когда объект делающий "emit signal" и объект, который подключился к этому сигналу Z>>>>в принадлежат разным потокам и использован QueuedConnection тип соединения.
M>Ну, я в общем не претендовал на доскональное знание кьютешных механизмов. Я спрашивал немного не об этом
Разве?
В изначальном вопросе были перечислены три разные альтернативы Qt(1), шаблон наблюдатель(2)
и очередь сообщений (3). И был вопрос:
M>Вот хочу узнать, как подобное можно красиво именно на плюсах реализовать
В нашем обсуждении, я надеюсь, вы уже увидели, что в Qt(1) реализовано и (2) и (3)
и еще один вариант. И даже разобрались, я надеюсь, как это можно красиво именно на плюсах реализовать.
Здравствуйте, Marty, Вы писали:
M>Здравствуйте! M>Вроде была уже тут такая тема, но я не смог найти, и к чему там пришли, тоже подзабыл M>Так что побаяню
M>Почему сюда — потому что интересуют не абстрактные архитектуры, а плюсовые решения.
Можешь еще boost::signals2 посмотреть, тот же Qt emit в однопоточном режиме, или вообще в сторону RabbitMQ посмотреть, тебе события внутрипрограммные нужны? Опиши задачу, опиши какие бибилиотеки используешь, может в них уже есть свои механизмы, так то можно и через boost::asio или libevent события обрабатывать.
Здравствуйте, Zhendos, Вы писали:
Z>Разве? Z>В изначальном вопросе были перечислены три разные альтернативы Qt(1), шаблон наблюдатель(2) Z>и очередь сообщений (3). И был вопрос:
M>>Вот хочу узнать, как подобное можно красиво именно на плюсах реализовать
Z>В нашем обсуждении, я надеюсь, вы уже увидели, что в Qt(1) реализовано и (2) и (3) Z>и еще один вариант. И даже разобрались, я надеюсь, как это можно красиво именно на плюсах реализовать.
В Qt это совсем не красиво. Мало того, что макросы, так ещё и внешний кодогенератор. Так что это даже не на плюсах.
Чтобы сделать красиво пересылку сообщений в C++ нужна либо рефлексия, либо шаблонные виртуальные функции.
Есть ещё красивый вариант с двойной диспетчеризацией, но на практике он не удобен.
Здравствуйте, B0FEE664, Вы писали:
BFE>В Qt это совсем не красиво. Мало того, что макросы...
Уже достоточно давно, в Qt5 добавили новый синтаксис — безо всяких макросов: https://wiki.qt.io/New_Signal_Slot_Syntax
BFE>...так ещё и внешний кодогенератор.
Чем плохо?
Внешний кодогенератор — в общем-то неплохая штука. Один из вариантов автоматизации разработок ПО.
BFE>Так что это даже не на плюсах.
Надстройка над C++ — так сказать корректнее.
P.S. Конечно же, в .NET инфраструктуре обработка сообщений и реализация паттерна Observer (наблюдатель) — выглядит более изящно.
Так ведь и .NET появился лет на двадцать позже, нежели C++
Здравствуйте, AlexGin, Вы писали:
BFE>>В Qt это совсем не красиво. Мало того, что макросы... AG>Уже достоточно давно, в Qt5 добавили новый синтаксис — безо всяких макросов: AG>https://wiki.qt.io/New_Signal_Slot_Syntax
Q_OBJECT остался.
BFE>>...так ещё и внешний кодогенератор. AG>Чем плохо? AG>Внешний кодогенератор — в общем-то неплохая штука. Один из вариантов автоматизации разработок ПО.
Внешний инструмент всегда требует существенных затрат на его настройку. Например, компиляция Qt кода из-под Visual Studio требует существенных временных затрат на настройку проекта.
BFE>>Так что это даже не на плюсах. AG>Надстройка над C++ — так сказать корректнее.
Надстройка над C++ — это уже не С++.
Здравствуйте, B0FEE664, Вы писали:
BFE>>>...так ещё и внешний кодогенератор. AG>>Чем плохо? AG>>Внешний кодогенератор — в общем-то неплохая штука. Один из вариантов автоматизации разработок ПО. BFE>Внешний инструмент всегда требует существенных затрат на его настройку. Например, компиляция Qt кода из-под Visual Studio требует существенных временных затрат на настройку проекта.
Ого, а можно подробности? У меня всегда былы скачай Add In, Next, Next, Install, пользуйся.
Здравствуйте, B0FEE664, Вы писали:
BFE>Внешний инструмент всегда требует существенных затрат на его настройку. Например, компиляция Qt кода из-под Visual Studio требует существенных временных затрат на настройку проекта.
Пользуюсь Qt v5.11.0 как совместно с MSVC-2017, так и с MSVC-2015.
Проект открывается сходу.
Настройка — однократная, для всего Qt VS Tools (Qt VS Addin), а не для каждого отдельного проекта.
Есть два варианта открыть проект:
1) Меню "Qt VS Tools"->"Open Qt Project File (.pro)..." — при этом создаётся проект .vcproj (в стандартах MSVS);
2) Если проект и солюшен были ранее созданы (открытием по 1-му варианту), то просто открываем из Меню "File"->"Recent...".