Functors in C++

Functors in C++

Functors in C++ are objects that can be called like a function as they provide many powerful features that many developers overlook sometimes. As functions play an important role in writing code efficiently, but sometimes we need a kind of function that retains state and works well with other functions or algorithms, then, functors are used. In this blog, we will discuss what a functor is, why it is useful, and how it can be implemented effectively in C++.

Table of Contents:

What is a Functor in C++?

A functor, or function object, is an object in C++ that can be called like a function using the operator(). Functors enable objects to act like functions while also maintaining state and encapsulating logic. It can be created by defining a class or structure that overloads the operator(). Also, functors are reusable and flexible.

Syntax of Functor:

class FunctorName {
public:
    // Overload the function call operator
    ReturnType operator()(ParameterList) {
        // Function body
    }
};

Example:

Cpp

Output:

The code shows how the functor object f acts like a function when f() is called.

Need for Functors over Normal Functions in C++

1. Normal functions cannot maintain data over many calls, whereas functors can, and so functors are required.

2. Functors coexist smoothly with algorithms such as std::sort, std::for_each, and std::transform, whereas normal functions don't.

3.  Functors are capable of accepting constructor arguments to specify dynamic behavior, whereas normal functions need additional parameters.

4.  Functors retain state and context and are thus suited for event-based programming.

5.  Functors may be inlined, which results in eliminating function call overhead over function pointers.

6. Functors enhance modularity and reusability by packaging data and function together.

Types of C++ Functors

There are three main types of functors in C++:

1. Generator Functors

A generator functor is a class overloaded for the operator(), which, when called, generates a sequence of values. It is useful when you require a stateful generator, e.g., generating unique identifiers, random numbers, or even Fibonacci numbers.

Example:

Cpp

Output:

The code shows how the functor is used to generate and fill the vector with the generated numbers from a given value using the std::generate.

2. Unary Functors

A unary functor is an object of a function that accepts a single argument and performs an operation on it. Unary functors are commonly used in the Standard Template Library (STL), especially with algorithms such as std::transform and std::for_each. It is a class that overloads the operator() with one parameter.

Example:

Cpp

Output:

The code shows how a functor is used to square numbers with the std::transform to compute the squared values.

3. Binary Functors

A binary functor is an object of a function that accepts two arguments and applies an operation to both of them. These functors are commonly used by STL algorithms, e.g., std::accumulate, std::sort, and std::transform (with two ranges of inputs). It is a class that overloads operator() with two parameters.

Example:

Cpp

Output:

The code shows how a functor is used for addition with the std::accumulate to compute the sum of the input values in a vector.

Implementing Functors in C++

You can easily create and implement the functors in C++. Below are a few steps to implement the functors.

Steps to Implement a Functor:  

Step 1: Create a class that will work as a function object.

Step 2: Implement the function logic inside the operator().

Step 3: Create an object of the class. 

Step 4: Finally, use the object as a function.

Example to explain the implementation:

Cpp

Output:

The code shows a functor is created, called, and used as a function in C++ programs.

Functors with Return Type and Parameter

A functor in C++ can accept parameters and return a value like a regular function. The return type depends on the logic that is implemented inside the operator().

Example:

Cpp

Output:

The code shows how a functor takes an integer as input, which means it accepts parameters and returns six times its value using the overloaded operator().

Functor with a Member Variable in C++

A functor with a member variable can store and change internal state and also retains values across multiple calls. It is useful for operations like counters, accumulators, and scaling factors.

Example 1: Stateful Counter Functor

Cpp

Output:

The code shows how a functor with a single member variable performs operations on inputs with a scaling factor.

Example 2: Functor with a Member Variable for Scaling

Cpp

Output:

The code shows how the functors are used with STL algorithms in their operator implementations.

Example 3: Functor with Multiple Member Variables

Cpp

Output:

The code shows how a functor with multiple member variables is used to uphold the running total of inputs with the scaling factor.

Functors with Standard Template Library(STL) in C++

Functors work comfortably with STL algorithms such as std::sort, std::for_each, and std::transform. They provide custom operations while keeping the code brief and efficient.

Example 1: Using Functor with std::sort

Cpp

Output:

The code shows how functor mode sorts a vector in descending order with the std::sort.

Example 2: Using Functor with std::for_each

Cpp

Output:

The code shows how the functor was used with std::for_each to print each number of the vector.

Retaining State in C++ Functor

Unlike regular functions, functors can retain state information by storing member variables. Thus, they allow carrying and changing data between calls.

How Functors Retain State

The functor has member variables to store values within the functor class and initialize the state upon creation of the functor, while the modified state is set in operator() on each call.

Example:

Cpp

Output:

The code shows how the functor retains its state, which constitutes a counter function updating its count.

Predefined Functors in C++

C++ offers predefined functors about the functional header, which can be readily used with STL algorithms. These functors perform common arithmetic operations, comparisons, and logic operations. There are four primary categories of predefined functors.

1. Arithmetic Functors

The arithmetic functors are predefined function objects defined in the functional header. They work for basic arithmetic operations and can be used with STL algorithms like std::transform. 

List of Arithmetic Functors

FunctorsOperation
std::plus<>Addition
std::minus<>Subtraction
std::multiplies<>Multipliation
std::divides<>Division
std::modulus<>Modulus
std::negate<>Negation

Example:

Cpp

Output:

The code shows how the arithmetic functors are used to perform basic mathematical operations on the integers.

2. Relational Functors

Relational functors are predefined function objects in the functional header that are used to compare two values and produce a Boolean result, true or false. They are most often used in STL algorithms such as std::sort, std::count_if, and std::remove_if.

List of Relational Functors

FunctorsOperation
std::equal_to<>Checks equality
std::not_equal_to<>Checks inequality
std::greater<>Checks if first parameter is greater
std::less<>Checks if the first parameter is smaller
std::greater_equal<>Checks greater or equal
std::less_equal<>Checks less than or equal

Example:

Cpp

Output:

The code shows how the relational functors are used to compare the integers and give 0 or 1 as an output.

3. Logical Functors

Logical functors are pre-defined function objects in the functional header that perform logical operations (AND, OR, NOT). They return a Boolean value, true or false, and are useful for filtering, conditional testing, and STL algorithms such as std::count_if and std::remove_if.

List of Logical Functors

FunctorsOperation
std::logical_and<>Logical AND (&&)
std::logical_or<>Logical OR
std::logical_not<>Logical NOT (!)

Example:

Cpp

Output:

The code shows how the pre-defined logical functors perform logical operations on the boolean values and give true or false as an output.

4. Bitwise Functors

Bitwise functors are predefined function objects in the functional header that execute bitwise operations (AND, OR, XOR, NOT). Bitwise functors are useful for bit manipulation, bit-level calculations, and bitmasks.

List of Bitwise Functors

FunctorsOperation
std::bit_and<>Bitwise AND (&)
std::bit_or<>Bitwise OR 
std::bit_xor<>Bitwise XOR (^)
std::bit_not<>Bitwise NOT (~)

Example:

Cpp

Output:

The code shows how the pre-defined bitwise functors perform bitwise operations on integers.

Functors vs Function Pointers in C++

Both functors (function objects) and function pointers enable functions to be passed as arguments, but they differ fundamentally in flexibility and application.

FeaturesFunctorsFunction Pointers
DefinitionObjects with operator()Pointer to a function
FlexibilityCan store state (variables, members)Stateless (cannot hold extra data)
PerformanceIt can be inlined, reducing function call overheadFunction calls have extra overhead
CustomizationIt can inherit, overload, and store extra dataFunction calls have extra overhead
Usage with STLWorks well with STL algorithmsFunction calls have extra overhead
Object-orientedSupports encapsulation & inheritanceNo encapsulation (raw function)

Example:

Cpp

Output:

The code shows the comparison between function pointers and functors for element-wise multiplication in a vector using std::transform.

Functors vs Virtual Functions in C++

Both virtual functions and functors (function objects) allow dynamic behavior in C++, but they have different uses and advantages.

FeaturesFunctorsVirtual Function
DefinitionObject with operator() overloadedMember function marked as virtual in a base class
Dynamic BehaviorAchieved using stored stateAchieved via runtime polymorphism (vtable)
PerformanceFaster (can be inlined by compiler)Slower (requires vtable lookup)
FlexibilityLow (no vtable usage)Higher (vtable pointer and function lookup)
Memory UsageLower (only object overhead)Higher (extra vtable pointer in objects)
Usage in STLWorks well with STL algorithmsNot usable directly with STL
EncapsulationNot tied to class hierarchyPart of a class hierarchy
Function OverridingNot possibleSupports overriding in derived classes

Example:

Cpp

Output:

The code shows how the functors are used for compile-time efficiency and virtual functions are used for runtime flexibility in modifying elements of the vector.

Functor with Lambda Compatibility in C++

A functor is a C++ design pattern that makes an object callable as if it were a function. Functors can be enhanced with lambda compatibility in modern C++ (C++11 and later).

Example:

Cpp

Output:

The code shows how the functor is used with std::function, which provides flexibility by supporting both functors and lambda expressions.

Conclusion 

Functors in C++ work as a function with better integration and a property of state retention, which provides us advantages in efficient programming. Understanding their advantages, types, and various uses provides us knowledge to develop more reusable and efficient code.

Functors in C++ - FAQs

1. What is a functor in C++?

A functor, or function object, is an object in C++ that can be called like a function using the operator().

2. Why use functors instead of normal functions?

You can use functors because they maintain state across calls, provide better integration with STL algorithms, support parameterized behavior, and can be inlined for better performance.

3. What are the types of functors in C++?

There are three main types of functors: Generator Functors, Unary Functors, and Binary Functors.

4. Why are the functors used with the Standard Template Library (STL)?

Functors are used with STL algorithms to customize their behavior efficiently.

5. How do functors improve performance?

Since functors can be inlined by the compiler, they avoid the overhead of function calls, making them more efficient than function pointers in many cases.

About the Author

Technical Research Analyst - Full Stack Development

Kislay is a Technical Research Analyst and Full Stack Developer with expertise in crafting Mobile applications from inception to deployment. Proficient in Android development, IOS development, HTML, CSS, JavaScript, React, Angular, MySQL, and MongoDB, he’s committed to enhancing user experiences through intuitive websites and advanced mobile applications.

Full Stack Developer Course Banner