Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
roth_stephan_clean_c20_sustainable_software_development_patt.pdf
Скачиваний:
29
Добавлен:
27.03.2023
Размер:
7.26 Mб
Скачать

Chapter 7 Functional Programming

Higher-Order Functions

A central concept in functional programming is so-called higher-order functions. They are the pendant to first-class functions. A higher-order function is a function that takes one or more other functions as arguments, or they can return a function as a result. In C++, any callable object—for example, an instance of the std::function wrapper, a function pointer, a closure created from a lambda expression, a handcrafted functor, and anything else that implements operator()—can be passed as an argument to a higher-­ order function.

We can keep this introduction relatively short, because we have already seen and used several higher-order functions. Many of the algorithms (see the section about algorithms in Chapter 5) in the C++ Standard Library are these kinds of functions. Depending on their purpose, they take a unary operator, unary predicate, or binary predicate and apply it to a container or to a sub-range of elements in a container.

Of course, despite the fact that the <algorithm> and <numeric> headers provide a comprehensive selection of powerful higher-order functions for different purposes, you can also implement higher-order functions or higher-order function templates by yourself. See Listing 7-24.

Listing 7-24.  An Example of Self-Made Higher-Order Functions

#include <functional> #include <iostream>

#include <vector>

template<typename CONTAINERTYPE, typename UNARYFUNCTIONTYPE> void myForEach(const CONTAINERTYPE& container, UNARYFUNCTIONTYPE unaryFunction) {

for (const auto& element : container) { unaryFunction(element);

}

}

template<typename CONTAINERTYPE, typename UNARYOPERATIONTYPE> void myTransform(CONTAINERTYPE& container, UNARYOPERATIONTYPE unaryOperator) {

322

Chapter 7 Functional Programming

for (auto& element : container) { element = unaryOperator(element);

}

}

template<typename NUMBERTYPE> class ToSquare {

public:

NUMBERTYPE operator()(const NUMBERTYPE& number) const noexcept { return number * number;

}

};

template<typename TYPE>

void printOnStdOut(const TYPE& thing) { std::cout << thing << ", ";

}

int main() {

std::vector<int> numbers { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; myTransform(numbers, ToSquare<int>());

std::function<void(int)> printNumberOnStdOut = printOnStdOut<int>; myForEach(numbers, printNumberOnStdOut);

return 0;

}

In this case, our two self-made higher-order function templates myTransform() and myForEach() are only applicable to entire containers because, unlike the Standard Library algorithms, they have no iterator interface. The crucial point, however, is that developers can provide custom higher-order functions that do not exist in the C++ Standard Library.

We will now look at three of these high-order functions in greater detail, because they play an important role in functional programming.

323