![]() |
![]() ![]() ![]() ![]() ![]() |
![]() |
Design RationaleBoost , The Boost C++ Libraries BoostBook Documentation Subset , Chapter 32. Boost.Signals
|
тянуть |
Толкать |
---|---|
struct pull_max { typedef int result_type; template<typename InputIterator> result_type operator()(InputIterator first, InputIterator last) { if (first == last) throw std::runtime_error("Empty!"); int max_value = *first++; while(first != last && *first <= 100) { if (*first > max_value) max_value = *first; ++first; } return max_value; } }; |
struct push_max { typedef int result_type; push_max() : max_value(), got_first(false) {} // returns false when we want to stop bool operator()(int result) { if (result > 100) return false; if (!got_first) { got_first = true; max_value = result; return true; } if (result > max_value) max_value = result; return true; } int get_value() const { if (!got_first) throw std::runtime_error("Empty!"); return max_value; } private: int max_value; bool got_first; }; |
В этих примерах следует отметить несколько моментов. Версия «pull» является многоразовым функциональным объектом, который основан на последовательности итератора ввода с целым числом<value_type
>и очень прост в дизайне. Модель «push», с другой стороны, опирается на интерфейс, специфичный для абонента, и обычно не используется повторно. Это также требует дополнительных значений состояния, чтобы определить, например, были ли получены какие-либо элементы. Хотя качество кода и простота использования, как правило, субъективны, модель «вытягивания» явно короче и более многоразовая и часто будет рассматриваться как более простая в написании и понимании, даже вне контекста библиотеки сигналов и усилителей.
Стоимость интерфейса комбинатора «pull» оплачивается при реализации самой библиотеки Сигналов. Чтобы правильно обрабатывать отключения слотов во время вызовов (например, когда вызывается оператор отсчета), необходимо построить итератор, чтобы пропустить отключенные слоты. Кроме того, итератор должен нести с собой набор аргументов для передачи в каждый слот (хотя достаточно ссылки на структуру, содержащую эти аргументы), и должен кэшировать результат вызова слота, чтобы множественные ссылки не приводили к нескольким вызовам. Это, по-видимому, требует большой степени накладных расходов, хотя, если рассматривать весь процесс вызова слотов, можно увидеть, что накладные расходы почти эквивалентны таковым в модели «толчка», но мы перевернули структуры управления, чтобы сделать комплекс итерации и отсчета (вместо того, чтобы делать комбинаторный комплекс определения состояния).
Повышаю. Сигналы поддерживают синтаксис соединения с формой<sig.connect(slot)
>, но был предложен более краткий синтаксис<sig += slot
>(и использовался другими сигналами и усилителями; реализациями слотов). Существует несколько причин, по которым этот синтаксис был отклонен:
Необязательно: синтаксис соединения, поставляемый Boost. Сигналы не менее мощные, чем у оператора<+=
>. Экономия при наборе текста<connect()
>против<+=
>по существу незначительна. Кроме того, можно утверждать, что призыв<connect()
>более читаемый, чем перегрузка<+=
>
Двусмысленный тип возврата: Существует неопределенность в отношении возвратного значения операции<+=
>: должна ли она быть ссылкой на сам сигнал, чтобы включить<sig += slot1 += slot2
>, или должна ли она возвращать<connection
>для вновь созданного соединения сигнал/слот?
Шлюз для операторов -=, +: При добавлении оператора связи<+=
>представляется естественным наличие оператора отключения<-=
>. Однако это создает проблемы, когда библиотека позволяет произвольным функциональным объектам неявно становиться слотами, потому что слоты больше не сопоставимы.
Вторым очевидным дополнением, когда у вас есть<operator+=
>, будет добавление оператора<+
>, который поддерживает добавление нескольких слотов, с последующим назначением сигнала. Однако это потребует реализации<+
>так, чтобы она могла принимать любые два функциональных объекта, что технически невозможно.
Класс 80 является основным пользовательским интерфейсом для автоматического управления временем жизни соединения, и его дизайн напрямую влияет на пользователей. Больше всего выделяются две проблемы: странное поведение копирования<trackable
>и ограничение, требующее от пользователей исходить из<trackable
>для создания типов, которые могут участвовать в автоматическом управлении соединением.
Поведение копирования<trackable
>по существу таково, что<trackable
>подобъекты никогда не копируются; вместо этого операция копирования является просто безоперационной. Чтобы понять это, мы смотрим на природу соединения сигнал-слот и отмечаем, что соединение основано на сущностях, которые соединяются; когда одна из сущностей разрушается, соединение разрушается. Поэтому, когда субобъект скопирован<trackable
>, мы не можем скопировать соединения, потому что соединения не относятся к целевой сущности - они относятся к исходной сущности. Эта причина двойственна той причине, что сигналы не копируются: слоты, подключенные к ним, подключены к этому конкретному сигналу, а не к данным, содержащимся в сигнале.
libsigc++— это библиотека сигналов и усилителей C++; библиотека слотов, которая первоначально начиналась как часть инициативы по обертыванию интерфейсов C библиотекамиGTKна C++ и выросла в отдельную библиотеку, поддерживаемую Карлом Нельсоном. Существует много сходств между libsigc++ и Boost.Signals. Сигналы находились под сильным влиянием Карла Нельсона и libsigc++. Беглый осмотр каждой библиотеки позволит найти аналогичный синтаксис для построения сигналов и при использовании соединений и автоматического управления временем подключения. Существуют некоторые различия в дизайне, которые разделяют эти библиотеки:
Определения слотов: Слоты в libsigc++ создаются с использованием набора примитивов, определенных библиотекой. Эти примитивы позволяют привязывать объекты (как часть библиотеки), явно адаптировать от аргумента и возвращать типы сигнала к аргументу и возвращать типы слота (libsigc++ по умолчанию более строг к типам, чем Boost.Signals). Обсуждение этого подхода с сопоставлением с подходом, принятым Boost. Сигналы даны в определении выбора слота.
Интерфейс комбинатора/маршаллера: эквивалент Boost. Комбинаторами сигналов в libsigc++ являются маршалы. Маршаллеры похожи на интерфейс «push», описанный в Combiner Interface, и там дается правильная трактовка темы.
Microsoftпредставила новую версию. NET Framework и связанный с ним набор языков и языковых расширений, одним из которых является делегат. Делегаты похожи на сигналы и слоты, но они более ограничены, чем большинство сигналов C++ и слотов в том, что они:
Требуется точное соответствие типа между делегатом и тем, что он называет.
Только возвращайте результат последней цели, названной, без возможности настройки.
Должен называть метод с<this
>уже связанным.
Статья Design Rationale раздела The Boost C++ Libraries BoostBook Documentation Subset Chapter 32. Boost.Signals может быть полезна для разработчиков на c++ и boost.
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.
:: Главная :: Chapter 32. Boost.Signals ::
реклама |