Question

C++ Functors Explained: What They Are and When to Use Them

cppfunctorfunction-objectfunction-call-operator

Question

I often hear about functors in C++. Can someone provide a clear overview of what they are and explain the situations where they are useful?

Short Answer

By the end of this page, you will understand what a functor in C++ is, how it relates to operator(), and why developers use functors in algorithms, sorting, customization, and stateful behavior. You will also see how functors compare with regular functions and lambdas.

Concept

In C++, a functor usually means an object that can be called like a function. This is also called a function object.

A class becomes a functor when it overloads the function call operator:

operator()()

That means instances of the class can be used with function-call syntax.

MyFunctor f;
f();

Even though f is an object, it behaves like a function.

Why this matters

Functors are useful because they combine two powerful ideas:

  • behavior: they can be called like functions
  • state: they can store data inside the object

A normal function can perform work, but it cannot easily carry per-instance state without using globals, static variables, or extra parameters. A functor can hold configuration inside the object itself.

Basic idea

class Greeter {
public:
    void operator()() const {
        std::cout << "Hello\n";
    }
};

Now this works:

Greeter g;
g();

Why C++ uses them a lot

Functors are common in the C++ Standard Library, especially with:

  • std::sort
  • std::find_if
  • std::for_each
  • std::transform
  • associative containers with custom ordering

For example, sorting can accept a comparison object:

std::sort(v.begin(), v.end(), MyComparator());

That comparator is often a functor.

Key benefit: stateful behavior

A functor can store values and use them later.

class Add {
    int amount;
public:
    Add(int a) : amount(a) {}

    int operator()(int x) const {
        return x + amount;
    }
};

Usage:

Add add5(5);
std::cout << add5(10); // 15

This is harder to express with a plain function unless you pass extra arguments every time.

Modern note

In modern C++, lambdas are often used instead of custom functor classes for short tasks. But lambdas themselves are implemented as callable objects, so understanding functors helps you understand lambdas too.

Mental Model

Think of a functor as a machine with a button.

  • A regular function is like a button on the wall: press it, and it runs.
  • A functor is like a small machine you own: it has a button and it can store settings inside.

For example:

  • a function is "add something"
  • a functor is "add 5" because the object remembers 5

So a functor is not just an action. It is an action plus stored data.

Take Quiz

Syntax and Examples

Core syntax

A class becomes a functor by overloading operator().

class Printer {
public:
    void operator()(const std::string& text) const {
        std::cout << text << "\n";
    }
};

Usage:

Printer print;
print("Hello");

Example 1: Simple functor

#include <iostream>

class Square {
public:
    int operator()(int x) const {
        return x * x;
    }
};

int main() {
    Square square;
    std::cout << square(4) << "\n"; // 16
}

Explanation

  • Square is a class
  • operator()(int x) makes the object callable
  • square(4) is translated to square.operator()(4)

Example 2: Stateful functor

#include <iostream>

class MultiplyBy {
    int factor;

public:
    MultiplyBy(int f) : factor(f) {}

    int operator()(int x) const {
        return x * factor;
    }
};

int main() {
    MultiplyBy times3(3);
    MultiplyBy times10(10);

    std::cout << times3(5) << "\n";  // 15
    std::cout << times10(5) << "\n"; // 50
}

Explanation

Each object stores its own factor.

  • times3 remembers 3
  • times10 remembers 10

Same class, different behavior based on stored state.

Example 3: Functor with std::sort

#include <algorithm>
#include <iostream>
#include <vector>

class Descending {
public:
    bool operator()(int a, int b) const {
        return a > b;
    }
};

int main() {
    std::vector<int> nums = {4, 1, 7, 3};
    std::sort(nums.begin(), nums.end(), Descending());

    for (int n : nums) {
        std::cout << n << ' ';
    }
}

Output:

7 4 3 1

Here the functor tells std::sort how to compare values.

Step by Step Execution

Consider this example:

#include <iostream>

class Add {
    int amount;
public:
    Add(int a) : amount(a) {}

    int operator()(int x) const {
        return x + amount;
    }
};

int main() {
    Add add5(5);
    int result = add5(10);
    std::cout << result << "\n";
}

Step-by-step

1. The class is defined

class Add {

This creates a blueprint for objects that can store an amount.

2. The object stores state

int amount;

Each Add object remembers its own value.

3. The constructor initializes the state

Add(int a) : amount(a) {}

When we create Add add5(5);, the object stores 5 in amount.

4. operator() makes the object callable

int operator()(int x) const {
    return x + amount;
}

This means the object can be used like a function.

5. The object is created

Add add5(5);

Now add5 is an object that remembers 5.

6. The object is called like a function

int result = add5(10);

This is equivalent to:

int result = add5.operator()(10);

7. The calculation happens

  • x is 10
  • amount is 5
  • result is 10 + 5 = 15

8. The result is printed

std::cout << result << "\n";

Output:

15

Real World Use Cases

1. Custom sorting

You often need to sort data in a special way.

Examples:

  • sort users by age
  • sort files by size
  • sort products by price descending

A functor can define the comparison logic.

2. Filtering and matching

Standard algorithms such as std::find_if and std::count_if accept callable objects.

Examples:

  • find the first inactive user
  • count numbers greater than a threshold
  • filter records matching a condition

A stateful functor can store that threshold.

3. Data transformation

With algorithms like std::transform, functors can modify values.

Examples:

  • convert temperatures
  • scale numbers
  • normalize data

4. Configuration-based behavior

A functor can hold settings.

Examples:

  • a formatter storing precision
  • a validator storing allowed ranges
  • a pricing rule storing a discount percentage

5. Associative containers with custom ordering

std::set and std::map can use custom comparison functors.

std::set<int, Descending> values;

This changes how elements are ordered internally.

Take Quiz

Real Codebase Usage

In real C++ projects, functors appear both directly and indirectly.

Common patterns

Guarded behavior

A functor may check conditions before doing work.

class PositiveOnly {
public:
    bool operator()(int x) const {
        return x > 0;
    }
};

This can be passed to algorithms like std::count_if.

Reusable comparison objects

Instead of repeating sorting logic inline, teams sometimes create named functors for clarity.

class SortByScore {
public:
    bool operator()(const Player& a, const Player& b) const {
        return a.score > b.score;
    }
};

This makes intent explicit.

Validation rules

A functor can encapsulate validation settings.

class MinLength {
    std::size_t min;
public:
    MinLength(std::size_t m) : min(m) {}

    bool operator()(const std::string& s) const {
        return s.size() >= min;
    }
};

Strategy-like behavior

Functors can act like small interchangeable policies.

Examples:

  • custom comparison rules
  • scoring formulas
  • pricing calculations
  • transformation rules

In modern code

Many codebases now prefer lambdas for short one-off logic:

std::sort(v.begin(), v.end(), [](int a, int b) {
    return a > b;
});

But named functors are still useful when:

  • logic is reused
  • the callable needs state
  • the type needs a descriptive name
  • the callable is part of a public API or template parameter

Common Mistakes

1. Forgetting to overload operator()

Broken code:

class MyFunctor {
public:
    void run() const {
        std::cout << "Hello\n";
    }
};

MyFunctor f;
f(); // error

Why it fails:

  • f() only works if operator() exists

Fix:

class MyFunctor {
public:
    void operator()() const {
        std::cout << "Hello\n";
    }
};

2. Confusing a functor with a regular function

A functor is an object, not just a function.

That means:

  • it can have member variables
  • it can have constructors
  • each instance can behave differently

3. Forgetting const when appropriate

Broken code:

class Compare {
public:
    bool operator()(int a, int b) {
        return a < b;
    }
};

This may still work in some cases, but many standard library uses expect callables that do not modify state.

Safer version:

class Compare {
public:
    bool operator()(int a, int b) const {
        return a < b;
    }
};

4. Writing overly complex functors for simple one-time logic

If the callable is tiny and used once, a lambda may be clearer.

std::sort(v.begin(), v.end(), [](int a, int b) {
    return a > b;
});

5. Using mutable state carelessly

If operator() changes internal data, repeated calls may produce surprising results.

class Counter {
    int count = 0;
public:
    int operator()() {
        return ++count;
    }
};

This is valid, but you should use it intentionally.

6. Forgetting that different objects can hold different state

MultiplyBy times2(2);
MultiplyBy times5(5);

These are separate objects with separate behavior. Beginners sometimes expect them to share state automatically.

Comparisons

ConceptWhat it isCan store state?Best use case
Regular functionNamed callable codeNoSimple reusable logic
FunctorObject with operator()YesReusable callable with state
LambdaAnonymous callable objectYes, via capturesShort inline behavior
Function pointerPointer to a functionNoInterfacing with older APIs

Functor vs regular function

  • A regular function is simpler
  • A functor can store data and configuration
  • A functor can also participate in templates as a type

Functor vs lambda

  • Lambdas are often shorter and easier for local use
  • Functors are useful when you want a named reusable type
  • Lambdas are essentially callable objects too

Functor vs function pointer

  • Function pointers only point to functions
  • Functors can hold state and have richer behavior
  • Templates often work very well with functors because the callable type is known at compile time

When to choose what

  • Use a regular function for simple shared logic with no state
  • Use a lambda for short local behavior
  • Use a functor class when the callable needs a name, reusable type, or stored configuration
Take Quiz

Cheat Sheet

Quick definition

A functor in C++ is an object that can be called like a function because it overloads operator().

Basic syntax

class MyFunctor {
public:
    ReturnType operator()(ParameterType value) const {
        // work
    }
};

Usage

MyFunctor f;
f(argument);

Equivalent to:

f.operator()(argument);

Why use functors

  • callable like functions
  • can store state
  • useful with STL algorithms
  • reusable named behavior

Common STL uses

std::sort(begin, end, comparator);
std::find_if(begin, end, predicate);
std::transform(begin, end, out, operation);

Example comparator

class Descending {
public:
    bool operator()(int a, int b) const {
        return a > b;
    }
};

Tips

  • add const to operator() when it does not modify object state
  • use functors when you need state or a named callable type
  • use lambdas for short one-off logic

Edge case

A functor can have multiple overloaded versions of operator().

class Printer {
public:
    void operator()(int x) const { std::cout << x; }
    void operator()(const std::string& s) const { std::cout << s; }
};

FAQ

What is a functor in C++?

A functor is an object that acts like a function because its class overloads operator().

Why use a functor instead of a normal function?

Use a functor when you want callable behavior that also stores state, such as configuration or parameters.

Are lambdas the same as functors?

Lambdas are not written the same way, but they are implemented as callable objects, so they are closely related to functors.

Are functors still used in modern C++?

Yes. Lambdas are more common for short local tasks, but functors are still useful for reusable named callables and stateful logic.

Where are functors used in the STL?

They are commonly used in algorithms like std::sort, std::find_if, std::transform, and in containers with custom comparators.

Can a functor keep internal data?

Yes. That is one of its main advantages over regular functions.

Is operator() required for a functor?

Yes. In common C++ usage, an object is considered a functor or function object when it defines operator().

Can functors return values?

Yes. operator() can return any valid type, just like a normal function.

Take Quiz

Mini Project

Description

Build a small C++ program that uses functors to process numbers in different ways. This project demonstrates the main reason functors are useful: they can behave like functions while storing their own configuration.

Goal

Create a program that sorts numbers in descending order and transforms numbers by adding a configurable value using functors.

Requirements

  • Create a functor that compares two integers in descending order.
  • Create a functor that adds a stored value to an integer.
  • Use std::sort with the comparison functor.
  • Use std::transform with the stateful add functor.
  • Print the results before and after transformation.
Take Quiz

Keep learning

Related questions

View more