{consumer(d), consumer(l), consumer(v)};
Объекты d
, l
и v
обернуты в вызов consumer(...)
. Он возвращает объекты функций, каждый из которых захватывает ссылки на один из объектов — d
, l
или v
. Хотя все объекты функций принимают в качестве параметров целочисленные значения, тот факт, что они захватывают абсолютно A
, B
и C
, когда сами типы не имеют
Чтобы это исправить, нужно найти std::function
. Объект типа std::function
может хранить любой объект функции или традиционную функцию, которая принимает целочисленный параметр и ничего не возвращает. С помощью полиморфизма он отвязывает тип от лежащего в его основе типа объекта функции.
Представьте, будто мы написали такой код:
std::function
[&vector](int x) { vector.push_back(x); });
Здесь объект функции, создаваемый на основе лямбда-выражения, обернут в объект типа std::function
, и всякий раз вызов f(123)
приводит к
При сохранении объектов функции экземпляры std::function
применяют некоторую логику. При захвате все большего и большего количества переменных лямбда-выражение будет увеличиваться. Если его размер относительно мал, то std::function
может хранить его внутри себя. Если же размер сохраненного объекта функций слишком велик, то std::function
выделит фрагмент памяти в куче и сохранит объект там. Возможности нашего кода в подобном случае затронуты не будут, но знать об этом нужно, поскольку такая ситуация может повлиять на его
std::function<...>
на самом деле выражает тип лямбда-выражения. Отнюдь. Это полиморфическая вспомогательная библиотечная функция, которая полезна для оборачивания лямбда-выражений и сокрытия различий в их типах.
Создаем функции методом конкатенации
Многие проблемы можно решить, не полагаясь исключительно на собственный код. Например, взглянем на то, как решается задача поиска уникальных слов в тексте на языке программирования Haskell. В первой строке определяется функция unique_words
, а во второй показывается ее использование на примере строки (рис. 4.2).
Ого! Программа получилась действительно короткой. Не вдаваясь особо в синтаксис языка Haskell, взглянем на то, что делает код. Определяется функция unique_words
, в которой к входным данным применяется набор функций. Сначала все символы преобразуются в строчные с помощью map toLower
. Таким образом, слова наподобие FOO и foo могут считаться words
разбивает предложение на отдельные слова. Например, из строки "foo bar baz"
мы получим массив ["foo", "bar", "baz"]
. Следующий шаг — сортировка нового списка слов. В результате последовательность слов ["a", "b", "a"]
будет выглядеть как ["a", "a", "b"]
. Теперь в дело вступает функция group
. Она группирует последовательные слова в списки, т.е. конструкция ["a", "a", "b"]
получит вид [["a", "a"], ["b"]]
. Задача практически выполнена, и теперь нужно сосчитать, сколько получилось групп одинаковых слов. В этом поможет функция length
.
Это замечательный стиль программирования, так как мы можем прочитать код справа налево, поскольку, по сути, описываем процесс преобразования предложения. Нет нужды знать, как реализованы отдельные фрагменты (если только они не будут работать слишком медленно и с ошибками).
Однако мы здесь не ради восхваления Haskell, а чтобы улучшить навыки работы с языком С++. Он позволяет написать аналогичный код. Мы не сможем достичь того же уровня элегантности, какой видели в языке Haskell, зато у нас под рукой самый быстрый язык программирования. В этом разделе показано, как инициировать
Как это делается
В данном примере мы определим несколько простых объектов функций и
1. Сначала включим несколько заголовочных файлов:
#include
#include
2. Далее реализуем вспомогательную функцию concat
, которая принимает множество параметров. Таковыми выступят функции наподобие f
, g
и h
, а результатом будет еще один объект функции, применяющий функции f(g(h(...)))
для любых входных данных.
template