Форумчанин
![]() ![]() ![]() 8216 / 5047 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Функторы, предикаты, функциональные адаптеры, лямбда-функции02.02.2014, 15:37. Показов 16245. Ответов 11
Вступление
Статья ориентирована на программистов С++, поверхностно знающих/желающих узнать STL, в особенности, с использованием его алгоритмов. Это краткий обзор по основным понятиям, в конце будет приведен список литературы для более полного ознакомления с материалом. Часто, алгоритмы STL имеют перегруженную версию или схожую по функционалу с добавлением в названии _if в конце, реализующуюся с применением функционального объекта или функции. Пример: copy - copy_if find - find_if equal includes sort accumulate и т.д. Это позволяет гибко подстраивать их в рамках определенной задачи. Функторы Функторы (их еще называют объект-функциями) - конструкция, которая предоставляет возможность использовать объект как функцию. Это может быть структура или класс, перегружающие оператор(). В языке С используется указатель на функцию. Конечно, подобная вещь оставлена для совместимости, но в реальности теряет смысл в использовании в С++, впрочем, не упомянуть о возможности было бы неверно. Пример использования функтора:
Часто, функциональные объекты делают шаблонными для лучшей возможности повторного использования кода.
Предикаты Предикаты- подмножество функторов, в которых тип возвращаемого значения operator() bool. Предикаты используются в алгоритмах сортировок, поиска, а также во всех остальных, имеющих на конце _if. Смысл в том, что объект-функция в случае использования предиката возвращает истину или ложь в зависимости от выполнения необходимого условия. Это либо удовлетворение объектом неких свойств, либо результат сравнения двух объектов по определенному признаку. Пример использования предиката:
Функциональные адаптеры Основные унарные и бинарные функциональные объекты, необходимые для сравнения, уже включены в STL и используются с добавлением хедера functional. Все они являются шаблонными классами и требуют определения необходимых операторов в типе данных, с которым работают. Примеры: std::greater<>, std::less<>. Следующий код сортирует элементы по убыванию с применением нашего объекта.
Пример: подсчитать количество элементов, больших (>), чем два.
Пример объединения адаптеров: подсчитать количество элементов, не больших !(>), чем два.
Лямбда-функции Наверное, самая приятная часть 11 стандарта, которая позволяет создавать очень гибкий код прямо на месте, не расползаясь мыслью по разным специальным классам и структурам, создаваемым для сравнения, а также повышающая читаемость кода в разы, ведь критерий сравнения или необходимая для выполнения функция определяется прямо рядом с местом использования. Тем не менее, это не отменяет использование всего того, что было озвучено выше, функциональные объекты имеют право на существование и должны использоваться там, где это действительно принесет полезный результат. Например, если необходимых инструкций для выполнения в теле функции достаточно много и определение данной функции на месте понизит удобочитаемость, или если у нас есть схожие куски кода и мы хотим вынести общий в одно место. В остальных случаях, данная конструкция будет очень удобна. Она обладает множеством различных тонкостей, мы лишь покажем общее с ней ознакомление, т.к. описание всех возможностей требовало бы отдельной статьи. Я покажу лишь использование конструкций с лямбда-функциями, и вы поймете, почему её так полюбили программисты. Пример: необходимо подсчитать количество неотрицательных элементов, кратных 7
Или же другой: вывести максимальный по модулю элемент
Например, следующий код значение каждого элемента увеличивает значение на единицу и выводит на экран.
Ниже приведен пример, в котором подсчитывается количество элементов, кратных k и больших, чем m.
Пример: подсчитать количество положительных элементов и отдельно количество четных, результат вывести на экран. Для простоты, используем алгоритм for_each.
Подведение итогов Я рассмотрел лишь часть функционала, впрочем вышло и так объемно. Лямбда-функции являются частью языка и не требует подключения дополнительных хедеров. Перед их использованием необходимо убедиться, что ваш компилятор поддерживает 11 стандарт, и установлен ключ -std=c++11 (или -std=c++0x). Также, лямбда-выражения доступны с использованием семейства библиотек boost. VS поддерживает лямбда-функции лишь с 2010 студии, для пользователей gcc и, соотв. mingw рекомендуется обновиться до/на основе версии 4.7.0 и выше.
За сим откланиваюсь. С уважением, MrGluck. Данная статья была написана специально для сайта онлайн тестов http://www.quizful.net/test Ссылка на первоисточник: http://www.quizful.net/post/fu... ers-in-STL Литература 1) Л.Аммераль - STL для программистов на С++, глава 6 (Функциональные объекты и адаптеры) 2) Дэвид Р.Мюссер, Жилмер Дж.Дердж, Атул Сейни - C++ и STL справочное руководство, 2 изд, глава 8 (Функциональные объекты), глава 23 (Справочное руководство по функциональным объектам и адаптерам) 3) http://en.cppreference.com/w/c... functional 4) http://cplusplus.com/reference/functional 5) http://en.wikipedia.org/wiki/A... on#C.2B.2B
13
|
02.02.2014, 15:37 | |
Ответы с готовыми решениями:
11
Предикаты\Функторы Стандартные функторы-адаптеры
|
03.02.2014, 10:46 | |
Тема сисек не раскрыта.
Спрашивается зачем плодить лишние классы Comp, Mult, DividedByTwo?
0
|
![]() ![]() |
|
04.02.2014, 13:59 | |
Лучше одни раз создать к примеру "Comp" и потом его использовать например в 10 алгоритмах, нежели городить лямбды, каждый раз.
Хорошо если тело лямбды короткое, а если нет то получается награмождение.
0
|
04.02.2014, 14:33 | ||||||
Avazart, в качестве функторов в SLT алгоритмах допускаются функции, объекты, лямды.
Объекты обычно используются для каррирования, задания начального значения функтора, агрегирования результата и т.д. Кликните здесь для просмотра всего текста
0
|
Форумчанин
![]() ![]() ![]() 8216 / 5047 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
|
|
04.02.2014, 15:00 [ТС] | |
Dmitriy_M, создайте вменяемо тип set со своим компаратором основываясь на функциях. Даже с лямбдами это не так элегантно и нагромождает код.
Не по теме: А почему бы не пользовать std::begin, std::end?
0
|
04.02.2014, 15:38 | |
0
|
Форумчанин
![]() ![]() ![]() 8216 / 5047 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
|
|||||||||||
04.02.2014, 17:30 [ТС] | |||||||||||
как нормально в параметрах set, например, задать свой компаратор с помощью функций?
http://www.cplusplus.com/reference/set/set/set/ Да, первый вариант можно слегка "улучшить" через лямбды, но я это к тому, что функции и функциональные объекты не одно и то же. Про необходимость дополнить статью примерами с использованием аргументированных конструкторов в классах, описывающих функциональные объекты я уже понял. Про внятное вступление с парой слов об алгоритмах STL и для чего иногда возникает в них потребность писать свои колбэки я тоже подметил. Если вы к этому вели, то спасибо. Есть еще несколько пунктов для правки статьи. Сейчас времени нет, как появится - сразу буду шлифовать и добавлять.
0
|
04.02.2014, 22:01 | |||||||||||
Внезапно
0
|
![]() |
||||||
04.02.2014, 22:19 | ||||||
Компаратор для set я так делал:
0
|
Форумчанин
![]() ![]() ![]() 8216 / 5047 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
|
|
05.02.2014, 02:41 [ТС] | |
Ну т.е. указатели на функцию во всех формах записи намного удобнее?
Посмотрите например Мюссер Д., Дердж Ж., Сейни Ф, - С++ и STL. Справочное руководство. Глава 8.2. Называется внезапно 1) вы уже сами указали, удобно передавать значения 2) эффективность т.к. Встраивание функционального объекта и функции не одно и то же. Я set всегда (кроме тех случаев когда хотел с указателями на функцию поизвращаться чисто из любопытства) задавал через параметр шаблона, и не нужно помнить, что последним параметром указатель на функцию передавать надо. Считай поведение меняется в одной строке, а не во всех точках вызовов конструктора.
2
|
06.02.2014, 15:03 | |
это не плюс, это причина по которой нужно использовать объект.
Есть тесты? Т.к. объект это то же оверхед, а что будет с -O3 вообще неизвестно. а в алгоритмах это нужно?
0
|
Модератор
![]() ![]() ![]() |
|
06.10.2015, 21:37 | |
MrGluck, отличная статья! В избранное, однозначно.
0
|
06.10.2015, 21:37 | |
Помогаю со студенческими работами здесь
12
STL функторы, предикаты Функциональные адаптеры Рекурсивные функции, функции высшего порядка, преобразование императивных программ в функциональные Встроенные предикаты. Предикаты взаимодействия, размещение данных
Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |
|
Опции темы | |
|
Новые блоги и статьи
![]() |
||||
Компиляция C++ с Clang API
NullReferenced 24.03.2025
Компиляторы обычно воспринимаются как черные ящики, которые превращают исходный код в исполняемые файлы. Мы запускаем компилятор командой в терминале, и вуаля — получаем бинарник. Но что если нужно. . .
|
Многопоточное программирование в C#: Класс Thread
UnmanagedCoder 24.03.2025
Когда запускается приложение на компьютере, операционная система создаёт для него процесс - виртуальное адресное пространство. В C# этот процесс изначально получает один поток выполнения — главный. . .
|
SwiftUI Data Flow: Передача данных между представлениями
mobDevWorks 23.03.2025
При первом знакомстве со SwiftUI кажется, что фреймворк предлагает избыточное количество механизмов для передачи данных: @State, @Binding, @StateObject, @ObservedObject, @EnvironmentObject и другие. . . .
|
Моки в Java: Сравниваем Mockito, EasyMock, JMockit
Javaican 23.03.2025
Как протестировать класс, который зависит от других сложных компонентов, таких как базы данных, веб-сервисы или другие классы, с которыми и так непросто работать в тестовом окружении? Для этого и. . .
|
Архитектурные паттерны микросервисов: ТОП-10 шаблонов
ArchitectMsa 22.03.2025
Популярность микросервисной архитектуры объясняется множеством важных преимуществ. К примеру, она позволяет командам разработчиков работать независимо друг от друга, используя различные технологии и. . .
|
Оптимизация рендеринга в Unity: Сортировка миллиона спрайтов
GameUnited 22.03.2025
Помните, когда наличие сотни спрайтов в игре приводило к существенному падению производительности? Время таких ограничений уходит в прошлое. Сегодня геймдев сталкивается с задачами совершенно иного. . .
|
Образование и практика
Igor3D 21.03.2025
Добрый день
А вот каково качество/ эффективность ВУЗовского образования? Аналитическая геометрия изучается в первом семестре и считается довольно легким курсом, что вполне справедливо. Ну хорошо,. . .
|
Lazarus. Таблица с объединением ячеек.
Massaraksh7 21.03.2025
Понадобилась представление на экране таблицы с объединёнными ячейками. И не одной, а штук триста, и все разные. На Delphi я использовал для этих целей TStringGrid, и то, кривовато получалось. А в. . .
|
Async/await в Swift: Асинхронное программирование в iOS
mobDevWorks 20.03.2025
Асинхронное программирование долго было одной из самых сложных задач для разработчиков iOS. В течение многих лет мы сражались с замыканиями, диспетчеризацией очередей и обратными вызовами, чтобы. . .
|
Колмогоровская сложность: Приёмы упрощения кода
ArchitectMsa 20.03.2025
Наверное, каждый программист хотя бы раз сталкивался с кодом, который напоминает запутанный лабиринт — чем дальше в него погружаешься, тем сложнее найти выход. И когда мы говорим о сложности кода, мы. . .
|