Лямбда-функции в качестве обработчиков событий зарекомендовали себя как удобный способ сократить объем кода. Как при определении событий обычных агентов. И тем более при определении ad-hoc-агентов.
Однако, в C++ есть еще один инструмент, который в последнее время широко используется наряду с лямбда-функциями -- это std::bind. Его поддержки в SO-5 нет.
Когда такая поддержка могла бы быть полезной?
Например, когда весь обработчик события -- это вызов какой-то внешней функции или метода какого-то стороннего объекта. Скажем, вот в таком случае (пример несколько надуманный, но может быть всякое):
structcreate_hash_request{conststd::uint_t*m_what;conststd::size_tm_size;...// Конструктор(ы)...};// Интерфейс устройства, которое эффективно выполняет криптографические операции.classcrypto_device{...};// Эти функции будут обеспечивать посторение разных// типов хешей с помощью заданного устройства.std::stringcreate_md5_hash(crypto_device*cd,constcreate_hash_request&req){...}std::stringcreate_sha1_hash(crypto_device*cd,constcreate_hash_request&req){...}std::stringcreate_sha256_hash(crypto_device*cd,constcreate_hash_request&req){...}// Под каждый тип хеша заводим своего агента,// который реагирует на запросы из отдельного mbox-а.crypto_device*cd=...;env.introduce_coop([cd](so_5::rt::agent_coop_t&coop){...coop.define_agent().event(md5_mbox,[cd](constcreate_hash_request&req){returncreate_md5_hash(cd,req);});coop.define_agent().event(sha1_mbox,[cd](constcreate_hash_request&req){returncreate_sha1_hash(cd,req);});coop.define_agent().event(sha256_mbox,[cd](constcreate_hash_request&req){returncreate_sha256_hash(cd,req);});});
На мой взгляд, проблема здесь в том, что определение подобных лямбд для ad-hoc агентов -- это лишняя работа, которую можно было бы не делать, если бы можно было писать так:
Проблема только в том, что так нельзя написать. Т.к. из возвращенного bind-ом объекта нельзя определить ни тип возвращаемого значения, ни тип аргумента (дабы по типу аргумента можно было понять, на какое именно сообщение нужно подписываться).
Обойти эту проблему можно за счет использования std::function:
Типы, к сожалению, нужно указывать по той же причине, по которой нужно указывать типа аргумента лямбды. Т.е. вот отсюда: event(mbox, [](const type &){...}) имя type вынуждено перекочевать вот сюда: bind_handler<type,...>(...).
У лямбд есть большое преимущество в том плане, что тип возвращаемого значения компилятор выводит сам. В случае же bind_handler его придется указать (если он отличен от void).
С другой стороны, у лямбды будут недостатки при больших capture-list-ах:
Мне кажется, что если в качестве главной претензии к лямбдам будет длинный capture-list, то наверное такая функциональность не нужна, потому что при желании сэкономить на символах, можно просто написать [&]. С другой стороны, много работ над интерфейсом SO выполняется после опроса общественного мнения, а значит аргумент в начале темы "В c++ широко используется, но в SO такой функциональности нет" в долгосрочной перспективе тоже может стать весомее.
Ну а если лично мое мнение: лямбды мне видятся более удобным средством.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Лямбда-функции в качестве обработчиков событий зарекомендовали себя как удобный способ сократить объем кода. Как при определении событий обычных агентов. И тем более при определении ad-hoc-агентов.
Однако, в C++ есть еще один инструмент, который в последнее время широко используется наряду с лямбда-функциями -- это std::bind. Его поддержки в SO-5 нет.
Когда такая поддержка могла бы быть полезной?
Например, когда весь обработчик события -- это вызов какой-то внешней функции или метода какого-то стороннего объекта. Скажем, вот в таком случае (пример несколько надуманный, но может быть всякое):
На мой взгляд, проблема здесь в том, что определение подобных лямбд для ad-hoc агентов -- это лишняя работа, которую можно было бы не делать, если бы можно было писать так:
Проблема только в том, что так нельзя написать. Т.к. из возвращенного bind-ом объекта нельзя определить ни тип возвращаемого значения, ни тип аргумента (дабы по типу аргумента можно было понять, на какое именно сообщение нужно подписываться).
Обойти эту проблему можно за счет использования std::function:
Что, на мой взгляд, даже хуже использования лямбды.
Однако, можно сделать тонкую обертку над function+bind и получить что-то вроде:
Либо, чуть более толстую обертку, которую можно будет использовать так:
Т.е. тут есть где покопаться. Однако первый вопрос вот какой: А нужно ли это вообще?
И, если нужно, то какой из вариантов предпочтительнее?
Лично я не вижу достаточных плюшек для того, чтобы вводить ещё один способ делать одно и то же.
Вот это выглядит отлично:
А вот появление нового класса, который шаблонный, да еще типы надо указывать:
Лично я, в этом случае, буду использовать лямбду, раз первый вариант невозможен.
Last edit: Nicolai Grodzitski 2015-04-10
Типы, к сожалению, нужно указывать по той же причине, по которой нужно указывать типа аргумента лямбды. Т.е. вот отсюда:
event(mbox, [](const type &){...})
имя type вынуждено перекочевать вот сюда:bind_handler<type,...>(...)
.У лямбд есть большое преимущество в том плане, что тип возвращаемого значения компилятор выводит сам. В случае же bind_handler его придется указать (если он отличен от void).
С другой стороны, у лямбды будут недостатки при больших capture-list-ах:
против:
Как раз то, что capture-list-ы могут быть длинными и заставило задуматься о bind_handler-е.
Мне кажется, что если в качестве главной претензии к лямбдам будет длинный capture-list, то наверное такая функциональность не нужна, потому что при желании сэкономить на символах, можно просто написать [&]. С другой стороны, много работ над интерфейсом SO выполняется после опроса общественного мнения, а значит аргумент в начале темы "В c++ широко используется, но в SO такой функциональности нет" в долгосрочной перспективе тоже может стать весомее.
Ну а если лично мое мнение: лямбды мне видятся более удобным средством.