What are C++ functors and their uses?

532,386

Solution 1

A functor is pretty much just a class which defines the operator(). That lets you create objects which "look like" a function:

// this is a functor
struct add_x {
  add_x(int val) : x(val) {}  // Constructor
  int operator()(int y) const { return x + y; }

private:
  int x;
};

// Now you can use it like this:
add_x add42(42); // create an instance of the functor class
int i = add42(8); // and "call" it
assert(i == 50); // and it added 42 to its argument

std::vector<int> in; // assume this contains a bunch of values)
std::vector<int> out(in.size());
// Pass a functor to std::transform, which calls the functor on every element 
// in the input sequence, and stores the result to the output sequence
std::transform(in.begin(), in.end(), out.begin(), add_x(1)); 
assert(out[i] == in[i] + 1); // for all i

There are a couple of nice things about functors. One is that unlike regular functions, they can contain state. The above example creates a function which adds 42 to whatever you give it. But that value 42 is not hardcoded, it was specified as a constructor argument when we created our functor instance. I could create another adder, which added 27, just by calling the constructor with a different value. This makes them nicely customizable.

As the last lines show, you often pass functors as arguments to other functions such as std::transform or the other standard library algorithms. You could do the same with a regular function pointer except, as I said above, functors can be "customized" because they contain state, making them more flexible (If I wanted to use a function pointer, I'd have to write a function which added exactly 1 to its argument. The functor is general, and adds whatever you initialized it with), and they are also potentially more efficient. In the above example, the compiler knows exactly which function std::transform should call. It should call add_x::operator(). That means it can inline that function call. And that makes it just as efficient as if I had manually called the function on each value of the vector.

If I had passed a function pointer instead, the compiler couldn't immediately see which function it points to, so unless it performs some fairly complex global optimizations, it'd have to dereference the pointer at runtime, and then make the call.

Solution 2

Little addition. You can use boost::function, to create functors from functions and methods, like this:

class Foo
{
public:
    void operator () (int i) { printf("Foo %d", i); }
};
void Bar(int i) { printf("Bar %d", i); }
Foo foo;
boost::function<void (int)> f(foo);//wrap functor
f(1);//prints "Foo 1"
boost::function<void (int)> b(&Bar);//wrap normal function
b(1);//prints "Bar 1"

and you can use boost::bind to add state to this functor

boost::function<void ()> f1 = boost::bind(foo, 2);
f1();//no more argument, function argument stored in f1
//and this print "Foo 2" (:
//and normal function
boost::function<void ()> b1 = boost::bind(&Bar, 2);
b1();// print "Bar 2"

and most useful, with boost::bind and boost::function you can create functor from class method, actually this is a delegate:

class SomeClass
{
    std::string state_;
public:
    SomeClass(const char* s) : state_(s) {}

    void method( std::string param )
    {
        std::cout << state_ << param << std::endl;
    }
};
SomeClass *inst = new SomeClass("Hi, i am ");
boost::function< void (std::string) > callback;
callback = boost::bind(&SomeClass::method, inst, _1);//create delegate
//_1 is a placeholder it holds plase for parameter
callback("useless");//prints "Hi, i am useless"

You can create list or vector of functors

std::list< boost::function<void (EventArg e)> > events;
//add some events
....
//call them
std::for_each(
        events.begin(), events.end(), 
        boost::bind( boost::apply<void>(), _1, e));

There is one problem with all this stuff, compiler error messages is not human readable :)

Solution 3

A Functor is a object which acts like a function. Basically, a class which defines operator().

class MyFunctor
{
   public:
     int operator()(int x) { return x * 2;}
}

MyFunctor doubler;
int x = doubler(5);

The real advantage is that a functor can hold state.

class Matcher
{
   int target;
   public:
     Matcher(int m) : target(m) {}
     bool operator()(int x) { return x == target;}
}

Matcher Is5(5);

if (Is5(n))    // same as if (n == 5)
{ ....}

Solution 4

Name "functor" has been traditionaly used in category theory long before C++ appeared on the scene. This has nothing to do with C++ concept of functor. It's better to use name function object instead of what we call "functor" in C++. This is how other programming languages call similar constructs.

Used instead of plain function:

Features:

  • Function object may have state
  • Function object fits into OOP (it behaves like every other object).

Cons:

  • Brings more complexity to the program.

Used instead of function pointer:

Features:

  • Function object often may be inlined

Cons:

  • Function object can not be swapped with other function object type during runtime (at least unless it extends some base class, which therefore gives some overhead)

Used instead of virtual function:

Features:

  • Function object (non-virtual) doesn't require vtable and runtime dispatching, thus it is more efficient in most cases

Cons:

  • Function object can not be swapped with other function object type during runtime (at least unless it extends some base class, which therefore gives some overhead)

Solution 5

Like others have mentioned, a functor is an object that acts like a function, i.e. it overloads the function call operator.

Functors are commonly used in STL algorithms. They are useful because they can hold state before and between function calls, like a closure in functional languages. For example, you could define a MultiplyBy functor that multiplies its argument by a specified amount:

class MultiplyBy {
private:
    int factor;

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

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

Then you could pass a MultiplyBy object to an algorithm like std::transform:

int array[5] = {1, 2, 3, 4, 5};
std::transform(array, array + 5, array, MultiplyBy(3));
// Now, array is {3, 6, 9, 12, 15}

Another advantage of a functor over a pointer to a function is that the call can be inlined in more cases. If you passed a function pointer to transform, unless that call got inlined and the compiler knows that you always pass the same function to it, it can't inline the call through the pointer.

Share:
532,386
uss
Author by

uss

About me.. check out my blog. :)

Updated on October 26, 2020

Comments

  • uss
    uss over 3 years

    I keep hearing a lot about functors in C++. Can someone give me an overview as to what they are and in what cases they would be useful?

  • Martin York
    Martin York over 15 years
    Just need to add that they can be used just like a function pointer.
  • Alecs
    Alecs over 12 years
    Can you explain this line, please std::transform(in.begin(), in.end(), out.begin(), add_x(1)); why you write there add_x, not the add42?
  • josesuero
    josesuero over 12 years
    @Alecs Both would have worked (but the effect would have been different). If I'd used add42, I would have used the functor I created earlier, and added 42 to each value. With add_x(1) I create a new instance of the functor, one which only adds 1 to each value. It is simply to show that often, you instantiate the functor "on the fly", when you need it, rather than creating it first, and keeping it around before you actually use it for anything.
  • Milad Khajavi
    Milad Khajavi about 11 years
    Can you explain these use case in real example? how can we use functors as polymorphism adn funtion pointer?
  • erogol
    erogol about 11 years
    What actually does mean that a functor holds state?
  • Gautam
    Gautam over 10 years
    The () operator is called the function-call operator. I guess you could also call it the parentheses operator.
  • zar
    zar over 10 years
    Can the functors have other member functions as well?
  • josesuero
    josesuero over 10 years
    @zadane of course. They just have to have the operator(), because that is what the caller uses to invoke it. What else the functor has of member functions, constructors, operators and member variables is completely up to you.
  • caub
    caub over 10 years
    std::transform(in.begin(), in.end(), out.begin(), [](int &i){ i+=1;});
  • johnbakers
    johnbakers about 10 years
    If your functor called different specific functions, and these other functions varied in the number of parameters they accept, does this mean your functor accepted a variable number of arguments for dispatching to these other functions?
  • MasonWinsauer
    MasonWinsauer about 10 years
    @LokiAstari - For those that are new to the concept, that could be a bit misleading. Functors can be "used like", but not always "in place of" function pointers. For example, a function that takes a function pointer cannot take a functor in its place even if the functor has the same arguments and return value as the function pointer. But by and large when designing, functors are the preferred and theoretically "more modern" way to go.
  • 463035818_is_not_a_number
    463035818_is_not_a_number over 9 years
    thanks for pointing out that one needs a base class to have some kind of polymorphism. I just have the problem that I have to use a functor in the same place as a simple function pointer and the only way I found was to write a functor base class (as I cannot use C++11 stuff). Wasnt sure if this overhead makes sense until i read your answer.
  • NathanOliver
    NathanOliver almost 9 years
    Shouldn't operator () be public in your first example since classes default to private?
  • Mateen Ulhaq
    Mateen Ulhaq over 8 years
    @crl Shouldn't that be std::transform(in.begin(), in.end(), out.begin(), [](int i) { return i + 1; });?
  • Lightness Races in Orbit
    Lightness Races in Orbit over 8 years
    "This parameter is actually the argument "parameterVar" passed by the constructor we just wrote" Huh?
  • einpoklum
    einpoklum over 8 years
    "unlike regular functions, they can contain state" <- umm, regular functions can have static variables, so - they can contain state, albeit the semantics are a bit dodgy.
  • rikimaru2013
    rikimaru2013 about 8 years
    @jalf class which defines the operator() function isn't class but it still functor.
  • srm
    srm about 8 years
    @rikimaru2013 In the parlance of functional programming, you're correct, a function is also a functor, but in the parlance of C++, the functor is specifically a class used as a function. The terminology was a bit abused early on, but the division is useful distinction and so persists today. If you start referring to functions as "functors" in a C++ context then you'll just confuse the conversation.
  • Nic
    Nic about 8 years
    Why does the second one return int when it should return bool? This is C++, not C. When this answer was written, did bool not exist?
  • Nic
    Nic about 8 years
    @Erogol A functor is an object which happens to support the syntax foo(arguments). Therefore, it can contain variables; for example, if you had an update_password(string) function, you might want to keep track of how often that had happened; with a functor, that can be a private long time representing the timestamp it last happened. With a function pointer or plain function, you'd need to use a variable outside of its namespace, which is only directly related by documentation and usage, rather than by definition.l
  • James Curran
    James Curran about 8 years
    @QPaysTaxes A typo I guess. I probably copy'n'pasted the code from the first example and forgot to change it. I've fixed it now.
  • Nic
    Nic about 8 years
    Oh, that makes sense. Thanks for bearing with my pedantry :)
  • Sergei Tachenov
    Sergei Tachenov almost 8 years
    Is it a class or an instance of the class? In most sources, add42 would be called a functor, not add_x (which is the class of the functor or just the functor class). I find that terminology consistent because functors are also called function objects, not function classes. Can you clarify this point?
  • Omu
    Omu over 7 years
    so this is like in javascript when you have function makeadd(bynumber){ return function(x){ return x + bynumber; }}
  • Euri Pinhollow
    Euri Pinhollow over 7 years
    It puzzled me for quite a while that you named std::transform a function. It isn't, it's a template which looks like a function in your code thanks to template parameter deduction.
  • armb
    armb over 7 years
    Article arguing that functor should correctly be used for this meaning (see also en.wikipedia.org/wiki/Functor), and that using it for function objects is just sloppy: jackieokay.com/2017/01/26/functors.html It may be too late for that though, given the number of answers here that only consider the function object meaning.
  • JoeManiaci
    JoeManiaci about 7 years
    I love when people not only explain something but also give the motivation for using it. Thank you.
  • sanjeev
    sanjeev over 6 years
    can you please explain the above scenario by quoting some part of code , i am new to c++ want to understand this concept..
  • StarDust
    StarDust over 6 years
    What's the advantage using over bool Is5(int n) {return 5==n;}
  • James Curran
    James Curran over 6 years
    @Riasat If Matcher is in a library, defining Is5() is quite simple. ANd you can create Is7(), Is32() etc. Further, that's just an example. THe functor could be much more complicate.
  • Hi-Angel
    Hi-Angel over 6 years
    ⁺¹ for mentioning that the name have been made up for no reason. I've just been searching for what's the relation between mathematical (or functional if you want) functor and the one from C++.
  • Euri Pinhollow
    Euri Pinhollow over 6 years
    @einpoklum functions can contain only one state unless you also pass the state (state itself or some value identifying state) as argument somehow.
  • Euri Pinhollow
    Euri Pinhollow over 6 years
    The answer is good but it lacks some important data which is obvious to experienced programmers but not so much to newbies: 1) only function templates have advantage of making it obvious for compiler what function was used. 2) If function accepts std::function<whatever(whatever)> then the advantage of inlining is lost. --------- When I first read this answer years ago it left me in buggy state because of argument deduction which hidden the fact that you cannot pass any object to non-template function.
  • mschmidt
    mschmidt over 6 years
    This answer should be the one with >700 Upvotes. As someone how knows Haskell better than C++, the C++ lingua puzzled me all the times.
  • Caleth
    Caleth about 6 years
    @EuriPinhollow when you pass arguments, e.g. std::transform(in.begin(), in.end(), out.begin(), add_x(1)), you have a function call. You are right that std::transform on it's own is not a function.
  • Euri Pinhollow
    Euri Pinhollow about 6 years
    One more comment: it is still possible to inline function even if it is passed as function object value. BUT: compilers are able to inline calls even if function is passed by pointer, you do not need to have a template for that. It's just that with function template you cannot pass function defined at run time.
  • Mateen Ulhaq
    Mateen Ulhaq almost 6 years
    Category theory and C++? Is this Bartosz Milewski's secret SO account?
  • Mateen Ulhaq
    Mateen Ulhaq almost 6 years
    It might be helpful to summarize the functor laws in standard notation: fmap(id, x) = id(x) and fmap(f ◦ g, x) = fmap(f, fmap(g, x)).
  • 463035818_is_not_a_number
    463035818_is_not_a_number over 5 years
    maybe at some point this answer deserves an update, since now lambdas are the easiest way to get a functor from whatever
  • copper.hat
    copper.hat over 5 years
    Thanks for elaborating the misleading use of the word functor.
  • Sisir
    Sisir over 5 years
    This is true. But with the new C++ 11 lambdas functors are pretty much dead. Now you may not need to create a whole class to have the function, instead have the function inlined in the method call. Lambdas are equally powerful in terms of both usage and performance.
  • Caleth
    Caleth almost 5 years
    @Sisir when you only have one operator(), sure. If you have a bunch of different operator()s sharing state then multiple lambdas are harder to get right than an explicit closure class
  • Caleth
    Caleth almost 5 years
    @mschmidt whilst functor also means this, C++ overloads the name to mean the same as "function object"
  • Paul Fultz II
    Paul Fultz II almost 5 years
    There is no mention of functor in the C++ standard. cppreference.com provides no definition of functor while it does provide a definition of FunctionObject with no mention of functor at all.
  • renardesque
    renardesque almost 5 years
    This (the matrix example) is plain use of operator() but not making use of function object properties.
  • rnpl
    rnpl over 4 years
    C++ and math terminology diverge in a lot of areas. This is neither undesirable nor wrong. E.g. "vector". Math concepts like "array", "sequence", "matrix" or "vector" have no equivalent in programming, because programming requires a concrete data type, which math is completely unconcerned with. In math you might talk about a sequence of numbers, but in programming this is meaningless. Are you talking about a list? a vector? a deque? The fact that some of these terms duplicate mathematical ones is fine. Even "function" does not have the mathematical meaning, which is why function object fails.
  • Franky
    Franky about 4 years
    What does std::transform(in.begin(), in.end(), out.begin(), add_x(1)); do at the first iteration, please?
  • Ray Eldath
    Ray Eldath almost 4 years
    I'm specifically curious about the name functor, is this have anything to do with functors in cats theory? I've just heard this word from some friends, and I know nothing of it, nor am I interested in that direction -- just curious.
  • user
    user almost 4 years
    Got an example?
  • phuclv
    phuclv over 3 years
    int C++11 there are std::function and std::bind
  • rturrado
    rturrado over 3 years
    I was looking exactly for this example because I have just seen it in a C++ course and I wasn't understanding it. Usually, we define an object of a class, which implements operator(), and pass it as an argument, a functor, to a function such as transform. However, in this case we are just constructing the object in the same call. Is that the only difference? That the functor goes out of scope and is destroyed once transform finishes? Thanks!