C++ Functors
In C++, a functor is an object that behaves like a function. In simpler terms, a functor is any object that overloads the function call operator (operator()
), allowing it to be called like a regular function. Functors are commonly used for passing behaviors to algorithms, storing function-like objects, and improving code modularity and reusability.
Functors are often used in the Standard Template Library (STL), particularly with algorithms like std::sort()
, where you might need custom comparison logic.
To create a functor, you define a class or struct and overload the function call operator (operator()
).
class Functor {
public:
// Overloading the function call operator
void operator()() {
std::cout << "Functor called!" << std::endl;
}
};
In the above code, operator()
allows an instance of Functor
to be called like a function.
#include <iostream>
// Functor class
class Printer {
public:
void operator()(const std::string& msg) const {
std::cout << "Message: " << msg << std::endl;
}
};
int main() {
Printer printer; // Create a functor object
printer("Hello, Functor!"); // Call it like a function
return 0;
}
Output:
Message: Hello, Functor!
In this example, the Printer
class has an overloaded operator()
that takes a string and prints it. You can call printer("Hello, Functor!")
just like a function.
Functors can also take parameters. This allows them to behave like functions that accept arguments.
#include <iostream>
// Functor class
class Adder {
public:
int operator()(int a, int b) {
return a + b;
}
};
int main() {
Adder add; // Create a functor object
int result = add(5, 10); // Call it like a function
std::cout << "Sum: " << result << std::endl;
return 0;
}
Output:
Sum: 15
In this example, the Adder
functor takes two integers and returns their sum when called.
Functors are commonly used in STL algorithms when you need to pass a custom function or comparison logic.
std::sort()
One common use of functors is to provide custom sorting logic to STL algorithms like std::sort()
.
#include <iostream>
#include <vector>
#include <algorithm>
// Functor class to compare two integers
class Compare {
public:
bool operator()(int a, int b) {
return a > b; // Sort in descending order
}
};
int main() {
std::vector<int> vec = {10, 30, 20, 50, 40};
// Use the functor to provide custom comparison to std::sort
std::sort(vec.begin(), vec.end(), Compare());
// Print the sorted vector
for (int num : vec) {
std::cout << num << " ";
}
return 0;
}
Output:
50 40 30 20 10
In this case, the Compare
functor defines a custom comparison operator to sort the vector in descending order.
Stateful Functions: Functors can maintain internal state between calls. This allows for more complex behaviors, like keeping track of the number of times a functor has been called.
class Counter {
private:
int count = 0;
public:
void operator()() {
count++;
std::cout << "Called " << count << " times." << std::endl;
}
};
Flexibility: Functors can be more flexible than regular function pointers. They allow for custom behavior and can store additional data or state, unlike plain functions.
Compatibility with STL: Many STL algorithms (like std::sort()
, std::for_each()
, etc.) work seamlessly with functors, allowing you to customize their behavior without needing to define separate functions.
In C++11 and later, you can use lambda expressions, which are function-like objects defined inline. Lambdas are similar to functors, but they're often shorter and easier to use in specific contexts.
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> vec = {10, 30, 20, 50, 40};
// Using a lambda expression to sort the vector in descending order
std::sort(vec.begin(), vec.end(), [](int a, int b) { return a > b; });
// Print the sorted vector
for (int num : vec) {
std::cout << num << " ";
}
return 0;
}
Output:
50 40 30 20 10
In this example, the lambda expression [](int a, int b) { return a > b; }
performs the same task as the Compare
functor in the previous example.
While both functors and lambdas can be used in similar scenarios, lambdas are generally more concise and easier to use, but functors are still preferred when you need to store state or reuse logic.
A key advantage of functors over lambda expressions is that they can maintain internal state. This is useful when you want to preserve information between calls.
#include <iostream>
// Functor with state
class Multiplier {
private:
int factor;
public:
Multiplier(int f) : factor(f) {}
int operator()(int num) {
return num * factor;
}
};
int main() {
Multiplier multiplyBy2(2); // Create a functor that multiplies by 2
std::cout << "2 * 5 = " << multiplyBy2(5) << std::endl; // Call the functor
return 0;
}
Output:
2 * 5 = 10
In this example, the Multiplier
functor maintains a factor
that can be customized when creating the functor object. This state can be used across multiple calls to the functor.