Welcome! Today, we're diving into an essential concept in functional programming: the Functor Design Pattern. You might ask, "What is a functor, and why should I care?"
As you might remember we talked about functors in the previous units. In C++ a "functor" usually refers to a class implementing the () operator, which can be called like a function. However, in more general terms, a functor is a different concept.
Generally speaking, Functors allow you to map a function over a structure, making your code clean and modular. By the end of this lesson, you'll know how to create and use functors in C++ to transform data structures effectively. Let’s get started!
First, let’s clarify what a functor is. In Functional Programming, a functor refers to an object, such as a class or a template class, that provides a method (transform or map) to apply a function to some specific element.
In more general terms, consider a template class F. This template class is considered a functor if it defines a map (or transform) method. This method should take two arguments:
- A value of type F<T1>.
- A function tthat transforms a value of typeT1to a value of typeT2.
The map (transform) method then applies the function to the value inside the structure F and returns a new structure F<T2> with the transformed value.
Let's see an example to understand this concept better.
First, let’s define the Functor class and understand each line of code step-by-step.
- template<typename T>: This specifies that- Functoris a template class parameterized by- T, which represents the type of the value inside the- std::optional.
- template<typename U>: This specifies that the- transformmethod is itself a template method, allowing different types for the input (- T) and output (- U) elements.
- std::optional<U> transform(const std::optional<T>& value, std::function<U(T)> func): This is the declaration of the- transformmethod.- It takes two parameters:
- const std::optional<T>& value: A constant reference to an optional holding an element of type- T.
 
 
- It takes two parameters:
The transform method implementation is key to understanding how the functor operates:
- if (value) { return func(*value); }: If the input optional has a value, apply the function- functo the dereferenced value and return the result wrapped in an optional.
- else { return std::nullopt; }: If the input optional is empty, return- std::nullopt.
This way, our functor can apply any function to any optional value safely, ensuring no problems appear.
Now let’s see how to define a simple function that can be used with the functor:
In this example, we have defined a simple function square that takes an integer x and returns its square.
Lastly, let’s incorporate the code into the main function to see the functor in action:
- Functor<int> optionalFunctor;: We create an instance of the- Functorclass specialized for- int.
- std::optional<int> opt = 5;: Define an- std::optionalholding an integer value.
- std::optional<int> result = optionalFunctor.transform<int>(opt, square);: Use the- transformmethod to apply the- squarefunction to the value inside- optand store the result in- result.
- The ifstatement andstd::coutprint the transformed value if it exists, showing the squared value25.
In this lesson, you've learned what functors are and how to use them for transforming data structures in C++. Functors help keep your code modular and reusable, making it simpler to apply functions across various containers.
Next, you'll have the chance to put this knowledge into practice. You'll be asked to create your own functors and apply different transformation functions to various containers.
Thanks for staying engaged throughout the lesson, and let’s move on to some hands-on practice to solidify your understanding!
