Std function c что это

Пишем свой std::function (boost::function)

Классы std::function и boost::function являются высокоуровневыми обертками над функциями и функциональными объектами. Объекты таких классов позволяют хранить и вызывать функции и функторы с заданной сигнатурой, что бывает удобно, например, при создании callback вызовов (например, мы можем регистрировать несколько обработчиков, и это могут быть как обычные функции, так и объекты с определенным оператором =)

Если вам интересно, каким образом реализуется данный функционал, то прошу под кат

Краткое введение, примеры использования

Если вы не знакомы с boost::function и std::function, то можно ознакомиться с ними здесь и здесь
std::function входит в стандарт языка c++11, и компиляторы gcc-4.7 и msvc-2012 его поддерживают (возможно, более ранние версии тоже имеют поддержку). В принципе, в рамках этой статьи можно считать реализацию от boost и стандартную полностью идентичными, так что пользоваться можно любой из реализаций

Собственно пример использования:

Переходим к самой реализации

Самая простая реализация, понятие Type erasure

В основе реализации данного класса лежит паттерн Type Erasure, более доступно можно почитать здесь Его предназначение заключается в том, что мы можем «спрятать» за одним интерфейсом различные сущности (объекты, указатели и пр.), которые предоставляют сходные возможности (например, осуществить вызов функции с тремя аргументами). Type erasure также можно представить как мостик, который связывает полиморфизм времени исполнения (runtime polymorfism) и полиморфизм времени компиляции (compile-time polymorfism).

Итак, переходим к реализации.
Мы будем использовать variadic templates из стандарта C++11. Например, gcc поддерживает этот функционал аж с версии 4.3, поэтому можно смело им пользоваться.

Не будем оригинальны и назовем наш класс function. Очевидно, что класс будет шаблонный, также очевидно, что у него будет один параметр шаблона — сигнатура (тип) вызываемой функции. Общая реализация шаблона отсутствует, вся работа будет происходить в частичной специализации шаблона. Частичная специализация нужна для того чтобы мы могли использовать типы аргументов и возвращаемого значения из нашей сигнатуры.
Сама реализация:

Класс function определяет оператор () соответствующий сигнатуре функции и передает управление методу invoke у класса function_holder_base. Этот класс имеет виртуальную функцию invoke, которая тоже совпадает с указанной сигнатурой (за исключением неявного параметра this).
Также класс function имеет шаблонный конструктор, который принимает один аргумент, в этом конструкторе создается наследник free_function_holder класса function_holder_base. Этот наследник является шаблонным классом — он сохраняет в себе переданный аргумент (обычно это функтор или указатель на функцию). В нем также определяется метод invoke, который вызывает сохраненный функтор с заданными аргументами.

В принципе, мы получили работоспособный аналог std::function и boost::function, мы вполне можем писать следующий код:
Переходим к улучшениям нашего класса:

Копируем поведение обычного указателя на функцию — оператор присваивания и конструктор копирования

Для того чтобы скопировать или присвоить объект мы должны уметь копировать (клонировать) указатель на базовый класс function_holder_base. Для этого расширим интерфейс этого класса следующим образом:

Делаем наш класс некопируемым (декларируем соответствующие оператор и конструктор в private секции), и добявляем метод clone, чтобы наследники сами определяли правильную стратегию клонирования.

Также, в класс function добавляются операторы присваивания и конструктор копирования:

Здесь мы используем auto_ptr и его разрушающее присваивание.

Осталось написать реализацию метода clone в наследнике — free_function_holder:

Вот собственно и все, теперь наш класс ведет себя как обычный указатель на функцию, и мы можем делать так:

Переходим к заключительной части:

Добавляем поддержку указателей на функции-члены

Поддержка указателей на методы у меня получилась довольно ограниченная: можно передавать объект к которому применяется указатель на метод только по значению (а хотелось бы еще по ссылке (const и не const) и по указателю (const и не const)), но в принципе для примера этого будет достаточно.

При использовании boost (std) и нашей реализации function придерживаемся правила, что первым аргументом должен идти объект, к которому применяется указатель на метод, соответственно аргументы теперь делятся на два вида: сам объект, и аргументы метода. Соответственно, у нас есть гарантия, что количество аргументов строго больше 0, этим мы и воспользуемся далее:

Реализация конструктора, который принимает указатель на метод тривиальна:

Мы сделали еще одного наследника function_holder_base специально для указателей на методы. Здесь используется особенность variadic templates: переменное количество типов (которое задается троеточием) можно расщепить на фиксированную часть, и остаток переменной длины (в котором количество типов меньше на размер фиксированной части). В конструкторе мы передаем в параметры шаблона фиксированную часть состоящую из одного типа — сигнатура функции, и произвольную часть — все остальное (это типы всех аргументов), а в реализации member_function_holder мы требуем, чтобы фиксированная часть состояла из двух элементов — сигнатура функции, класс, в котором находится наш метод, и аргументы непосредственно для вызова (здесь мы как раз используем указанную выше гарантию, что количество всех аргументов строго больше 0). Таким образом, мы сохраняем указатель на метод в конструкторе, и вызываем его в реализации метода invoke.

Отдельно хочется сказать про крайне неудобный и неинтуитивный способ декларирования типа «указатель на метод» и про способ вызова такого метода. По этому поводу в C++ FAQ есть предупреждение, о том как минимизировать количество головной боли при работе с указателями на методы (я полчаса гуглил, как записать правильно это выражение)

Источник

Читайте также:  что нельзя делать при глаукоме и катаракте

Класс function

Программа-оболочка для вызываемого объекта.

Синтаксис

Параметры

фти
Тип функции для заключения в оболочку.

Политике
Функция распределителя.

Комментарии

Некоторые функции-члены принимают операнд с именем нужного целевого объекта. Такой операнд можно задать несколькими способами:

fn — вызываемый объект fn ; после вызова объект function содержит копию fn ;

fnref — вызываемый объект, который именует fnref.get() ; после вызова объект function содержит ссылку на fnref.get() ;

right — вызываемый объект, при наличии, который содержится в объекте function right ;

npc — указатель null; после вызова объект function пуст.

Пустой объект function не содержит вызываемый объект или ссылку на вызываемый объект.

Члены

Конструкторы

Имя Описание
function Создает оболочку, которая является пустой или содержит вызываемый объект произвольного типа с фиксированной сигнатурой.

Определения типов

Функции

Имя Описание
assign Присваивает вызываемый объект данному объекту функции.
swap Меняет местами два вызываемых объекта.
target Проверяет, является ли вызываемый объект вызываемым, как указано.
target_type Возвращает сведения о типе в вызываемый объект.

Операторы

Имя Описание
оператор не указан Проверяет, существует ли вызываемый объект.
оператор () Вызывает вызываемый объект.
Оператор = Заменяет хранимый вызываемый объект.

assign

Присваивает вызываемый объект данному объекту функции.

Параметры

_Func
Вызываемый объект.

_Fnref
Оболочка ссылки, которая содержит вызываемый объект.

Политике
Объект распределителя.

Комментарии

function

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

Параметры

Правильно
Объект функции для копирования.

FX
Тип вызываемого объекта.

_Func
Вызываемый объект, для которого создается оболочка.

Идентификатор
Тип распределителя.

_Fnref
Ссылка на вызываемый объект для упаковки.

Комментарии

Пример

оператор не указан

Проверяет, существует ли вызываемый объект.

Комментарии

Пример

operator()

Вызывает вызываемый объект.

Параметры

TN
Тип N-го аргумента вызова.

Код
N-й аргумент вызова.

Комментарии

Пример

operator=

Заменяет хранимый вызываемый объект.

Параметры

нпк
Константа указателя null.

Правильно
Объект функции для копирования.

FN
Вызываемый объект, для которого создается оболочка.

фнреф
Ссылка на вызываемый объект для упаковки.

Комментарии

Пример

result_type

Возвращаемый тип хранимого вызываемого объекта.

Комментарии

typedef — синоним типа Ret в сигнатуре вызова шаблона. Его можно использовать, чтобы определить возвращаемый тип упакованного вызываемого объекта.

Пример

Меняет местами два вызываемых объекта.

Параметры

Правильно
Объект функции для обмена.

Комментарии

Пример

target

Проверяет, является ли вызываемый объект вызываемым, как указано.

Параметры

Fty2
Тип целевого вызываемого объекта для проверки.

Комментарии

Пример

target_type

Возвращает сведения о типе в вызываемый объект.

Комментарии

Источник

Std function c что это

Статья об использовании std::function

Поводом для написания данной статьи стало желание систематизировать всё то, чему я научился в процессе кодинга лаб по таким предметам, как Численные методы; Уравнения математической физики; Методы оптимизации. Надеюсь эта статья будет полезна не только людям, которые учатся в НГТУ на факультете ФПМИ, но и широкому кругу читателей.

В Си/C++ имеется возможность передавать функцию в качестве аргумента функции как указатель на функцию. Вы наверняка знаете этот страшный синтаксис:

Причём, в отличие от Си, в C++ таким образом можно описывать любой функциональный объект, то есть объект, допускающий вызов операции () :

Аналогичным образом можно использовать лямбды:

Таким образом, можно передавать функции в качестве аргументов функций.

Численное вычисление производной

Но писать для каждой функции другую функцию, вычисляющую её производную непрактично! Поэтому такую проблему можно решить с помощью std::function :

Данная функция получает функцию, и возвращает функцию, которая считает её производную. Пример использования:

А далее представлен код для вычисления первой и второй производных функций, взятый из курсовой по УМФ, смело используйте его в своих проектах.

Пример использования std::bind

Автоматический расчет правой части

В таком предмете, как УМФ требуется решить следующее дифференциальное уравнение:

где u = u(x, y, t) является неизвестной функцией. Для численного решения используется Метод Конечных Элементов.

Для декартовых координат это уравнение раскладывается в lambda*(d^2 u/dx^2 + d^2 u/dy^2) + gamma * u + sigma * du/dt = f

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

Код взят опять же из репозитория по УМФ.

Это избавляет от лишней рутины ручного вычисления производных для функций при тестировании, автоматизируя этот процесс, также снижается вероятность ошибиться.

Обертка для подсчета вызовов функции

Это можно сделать не вмешиваясь в код этого метода, явным образом выставляя count++ при каждом вызове функции, послав вместо функции обёртку над ней:

У нас стоит задача замерить время работы какого-то кода. Можно поступить следующим образом:

Но это решение плохо тем, что нам постоянно надо копировать эти участки кода, и мы потенциально можем потерять начало или конец замера времени, поэтому можно воспользоваться концепцией RAII, и сделать это следующим красивым образом, передав в функцию замера времени лямбду кода, время которого будет замеряться:

Притом мы не теряем локальные переменные благодаря использованию лямбд.

Предположим, что у нас есть функция вычисления интеграла одномерной функции:

Тогда двойной интеграл двумерной функции можно вычислить следующим образом:

Некоторые люди делают это с помощью копипаста, но думаю не стоит вам объяснять чем плох копипаст по сравнению с этим подходом.

В МО многомерные методы нахождения минимума функции используют одномерную функцию оптимизации. И было задание задавать различные методы одномерной оптимизации, чтобы протестировать их эффективность конкретно в этой среде. Ну раз так, то мы не будем в программе жестко задавать функцию одномерной оптимизации, а будем передавать её как аргумент функции многомерной оптимизации:

На самом деле я не использовал это на практике, а пример этого паттерна взял из библиотеки дифференциальной эволюции.

Там же можно увидеть паттерн termination strategy, при помощи которого можно передавать в метод функцию, которая будет решать когда завершать метод. Но в рамках нашей учебной программы это излишная абстракция, и различные стратегии завершения метода никогда не применятся.

Инкапсулируем с помощью std::function

В УМФ у нас есть задача получить конечно-элементную аппроксимацию функции на основе правой части дифференциального уравнения и сетки конечных элементов. Учитывая эту информацию, решатель МКЭ может выглядеть следующим образом:

Поэтому мы должны каким-то образом внутри функции решения дифференциального уравнения выставлять краевые условия.

Но это ужасный стиль! Зачем нам находить значение функции при помощи численных методов, которую мы уже знаем? Это выглядит как бред, поэтому более красивым может быть передавать функцию, которая выставляет краевые условия:

Это очень красивое решение, которое может быть применено при решении реальных задач, если мы реально не знаем истинную функцию, но знаем значения краевых условий. Это значительно повышает абстрактность кода, позволяет его использовать в других проектах.

Так как вы можете использовать это на практике, более подробно смотрите код из курсовой по УМФ:

About

Статья о применении std::function в универе для лаб

Источник

С++ std::functional

Functional заголовочный файл в стандартной библиотеке языка программирования C++, предоставляющий набор шаблонов классов для работы с функциональными объектами, а также набор вспомогательных классов для их использования в алгоритмах стандартной библиотеки.

Функциональный объект

может быть использован следующим образом:

У использования функциональных объектов есть ряд преимуществ перед использованием функций, а именно:

Предикаты

Обёртки функций

std::function

Начиная со стандарта C++11 шаблонный класс std::function является полиморфной обёрткой функций для общего использования. Объекты класса std::function могут хранить, копировать и вызывать произвольные вызываемые объекты — функции, лямбда-выражения, выражения связывания и другие функциональные объекты. Говоря в общем, в любом месте, где необходимо использовать указатель на функцию для её отложенного вызова, или для создания функции обратного вызова, вместо него может быть использован std::function, который предоставляет пользователю большую гибкость в реализации.

Определение класса std::function

Оператор приведения function к булевскому типу возвращает true, когда у класса есть целевой объект.

std::bad_functional_call

Исключение типа bad_functional_call будет брошено при попытке вызова обёртки функции function::operator(), если у этой обёртки отсутствует целевой объект. bad_functional_call наследуется от std::exception, и у него доступен виртуальный метод what() для получения текста ошибки. Пример использования:

std::mem_fn

Шаблонная функция std::mem_fn создаёт объект-обёртку вокруг указателей на члены класса. Этот объект может хранить, копировать и вызывать член класса по указателю. В качестве указателя могут также использоваться ссылки и умные указатели.

Связыватели

std::bind

Шаблонная функция std::bind называется связывателем и предоставляет поддержку частичного применения функций. Она привязывает некоторые аргументы к функциональному объекту, создавая новый функциональный объект. То есть вызов связывателя эквивалентен вызову функционального объекта с некоторыми определёнными параметрами. Передавать связывателю можно или непосредственно значения аргументов, или специальные имена, определенные в пространстве имен std::placeholders, которые указывают связывателю на то, что данный аргумент не будет связан, и определяют порядок аргументов у возвращаемого функционального объекта.

Определение функции std::bind

std::placeholders

Для получения целого числа k из заполнителя _K предусмотрен вспомогательный шаблонный класс std::is_placeholder. При передаче ему заполнителя, как параметра шаблона, есть возможность получить целое число при обращении к его полю value. К примеру, is_placeholder ::value вернёт 3.

Функциональные объекты

Для создания объектов reference_wrapper предоставлены вспомогательные функции ref и cref, определённые следующим образом:

Источник

Std function c что это

Этот браузер больше не поддерживается.

Выполните обновление до Microsoft Edge, чтобы воспользоваться новейшими функциями, обновлениями для системы безопасности и технической поддержкой.

Требования

Заголовок: возможностей>

Пространство имен: std

Remarks

Для алгоритмов требуются два типа объектов функций: Унарные и двоичные. Унарным объектам-функциям требуется один аргумент, и бинарным — два аргумента. Объект-функция и указатели на функции могут передаваться как предикат для алгоритма, но объекты-функции также могут настраиваться и расширяют область, а также повышают гибкость и эффективность стандартной библиотеки C++. Если, например, требуется привязать значение к функции перед передачей алгоритму, указатель на функцию не может использоваться. Адаптеры функций преобразуют указатели на функции в гибкие объекты-функции, которые можно привязать к значению. также содержит адаптеры функций элементов, которые позволяют вызывать функции членов как адаптируемые объекты функций. Функции могут настраиваться, если у них есть объявления вложенных типов, указывающие типы аргументов и типы возвращаемого значения. Объекты-функции и их адаптеры позволяют стандартной библиотеке C++ обновить существующие приложения и облегчают интеграцию библиотеки в среду программирования C++.

В C++ 11, C++ 14 и C++ 17 добавлены следующие функции:

Сигнатура вызова — имя типа возвращаемого значения, за которым следует список разделенных запятыми из нуля или более типов аргументов, заключенный в круглые скобки.

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

Вызываемый объект — это объект вызываемого типа.

Тип оболочки вызова — это тип, который содержит вызываемый объект и поддерживает операцию вызова, которая перенаправляет на этот объект.

Оболочка вызова — это объект типа оболочки вызова.

Целевой объект — это вызываемый объект, который содержится в объекте оболочки вызова.

Если у оболочки вызова есть слабый результирующий тип, тип его члена основан на типе T целевого объекта оболочки, как показано ниже:

В противном случае член result_type не существует.

У каждой оболочки вызова есть конструктор перемещения и конструктор копирования. Простая оболочка вызова — это оболочка с оператором присваивания, конструктор копирования, конструктор перемещения и оператор присваивания которой не вызывают исключений. Пересылающая оболочка вызова — это оболочка, которая может вызываться с помощью списка произвольных аргументов и которая предоставляет аргументы вызываемому объекту в оболочке в виде ссылок. Все аргументы rvalue предоставляются как ссылки rvalue, а аргументы lvalue — как ссылки lvalue.

Источник

Читайте также:  запах пыли в носу симптомы чего это может
Образовательный портал