Why Use Functors Over Functions

Why use functors over functions?

At least four good reasons:

Separation of concerns

In your particular example, the functor-based approach has the advantage of separating the iteration logic from the average-calculation logic. So you can use your functor in other situations (think about all the other algorithms in the STL), and you can use other functors with for_each.

Parameterisation

You can parameterise a functor more easily. So for instance, you could have a CalculateAverageOfPowers functor that takes the average of the squares, or cubes, etc. of your data, which would be written thus:

class CalculateAverageOfPowers
{
public:
CalculateAverageOfPowers(float p) : acc(0), n(0), p(p) {}
void operator() (float x) { acc += pow(x, p); n++; }
float getAverage() const { return acc / n; }
private:
float acc;
int n;
float p;
};

You could of course do the same thing with a traditional function, but then makes it difficult to use with function pointers, because it has a different prototype to CalculateAverage.

Statefulness

And as functors can be stateful, you could do something like this:

CalculateAverage avg;
avg = std::for_each(dataA.begin(), dataA.end(), avg);
avg = std::for_each(dataB.begin(), dataB.end(), avg);
avg = std::for_each(dataC.begin(), dataC.end(), avg);

to average across a number of different data-sets.

Note that almost all STL algorithms/containers that accept functors require them to be "pure" predicates, i.e. have no observable change in state over time. for_each is a special case in this regard (see e.g. Effective Standard C++ Library - for_each vs. transform).

Performance

Functors can often be inlined by the compiler (the STL is a bunch of templates, after all). Whilst the same is theoretically true of functions, compilers typically won't inline through a function pointer. The canonical example is to compare std::sort vs qsort; the STL version is often 5-10x faster, assuming the comparison predicate itself is simple.

Summary

Of course, it's possible to emulate the first three with traditional functions and pointers, but it becomes a great deal simpler with functors.

What are C++ functors and their uses?

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.

When should you ever use functions over functors in C++?

Functions support distributed overriding. Functors do not. You must define all of the overloads of a Functor within itself; you can add new overloads of a function anywhere.

Functions support ADL (argument dependent lookup), permitting overloading in the argument-type associated namespace. Functors do not.

Function pointers are (kind of) a type-erased stateless functor that is a POD, as evidenced by how stateless lambdas convert into it. Such features (POD, stateless, type erasure) are useful.

Advantage of C++ functor use for comparison

The primary use of functors is to create functions at runtime that possess some state. This is important in scenarios where you need a function to possess some information, but you cannot pass this information into the function as a parameter. One common example of this is in algorithms like std::sort where the comparator function must take only two arguments (the things to compare) so you cannot just pass in extra information as parameters. You must instead create a function object at runtime and pass in that information in the constructor.

This is essentially what you do when you call

 sort( localList.begin(), localList.end(), Sorter( 100 ) );

You are creating a Sorter function wherein you pass the information about the 100 when constructing the function. Calling it still requires only two parameters so this will work in the std::sort algorithm. There is no way to do this with regular functions, besides things like std::bind.

Template functors vs functions

There are two main reasons: The first is, as pythonic metaphor noted, partial specialization is only valid for classes and not functions. Note that functions can use overloads to overcome this problem generally, but often if you are doing metaprogramming it's easier and more generic to use partial specialization. I'd actually think this was the main reason.

The second reason is that anytime that code wants to accept a function object (like in the STL, e.g. std::transform), it will have a type template parameter. If you pass a functor or a lambda, the exact type is known at compile time, and you don't pay for indirection, and inlining can be performed. If you pass a function pointer (or a std::function), only the signature is known at compile time, and you pay for an indirection (and you can't inline). For instance, std::sort can be considerably faster with a functor than a function pointer.

Note that there is a little used feature called function pointer template parameters; these are non type template parameters that specialize on a specific function, and thus can remove indirection. However, if you use one of these, you can't use a functor at all. So most code that wants to accepts a function object does it the way I described above.

function pointer vs functors in C++

For one, the functor can contain internal state; a state that is valid for this invocation of the function object only. You could add static variables to your function, but those would be used for any invocation of the function.

Second, the compiler can inline calls to the functor; it cannot do the same for a function pointer. This is why C++ std::sort() beats the crap out of C qsort() performance-wise.

What exactly it means that functor in c++ have a state and other regular function doesnt have a state?

"State" refers to data that is remembered and carried between subsequent calls to a function or class method.

Your MyFuncPtr is stateful, as it carries a data member a whose value is set in MyFuncPtr's constructor and is remembered and used through all calls to MyFuncPtr::operator(). You are setting the state once, and then using it over and over. You could just as easily update the state instead, by have MyFuncPtr::operator() save the new value into a and then expose another class method to retrieve the current value of a when needed.

In your example, sum() is also stateful, as it is not a free function, it is actually a non-static member of MyFuncPtr, and thus has access to the same state data (MyFuncPtr::a) that MyFuncPtr::operator() has access to. A better example of a stateless sum() would look more like this instead:

class MyFuncPtr
{
public:
int a;

int operator ()(int b)
{
return a + b;
}

MyFuncPtr(int val)
{
a = val;
}
};

int sum(int a, int b)
{
return a + b;
}

int main()
{
cout << "Hello World!\n";

MyFuncPtr obj(5);
cout << obj(15) << endl;

cout << sum(5, 15) << endl;
}

What are functors, and why do we need them?

Don't think of functors as that 'They're named "functors" to annoy category theory fanboys and language purists.' :)

Their use is mainly to generate boilerplate or template code. Just like C++ templates are an optimization feature because generic dispatch can be slow, so are Factor functors.

Example here:

USING: functors io lexer namespaces ;
IN: examples.functors

FUNCTOR: define-table ( NAME -- )

name-datasource DEFINES-CLASS ${NAME}-datasource

clear-name DEFINES clear-${NAME}
init-name DEFINES init-${NAME}

WHERE

SINGLETON: name-datasource

: clear-name ( -- ) "clear table code here" print ;

: init-name ( -- ) "init table code here" print ;

name-datasource [ "hello-hello" ] initialize

;FUNCTOR

SYNTAX: SQL-TABLE: scan-token define-table ;

You can now write SQL-TABLE: person and Factor will create the words clear-person, init-person and person-datasource for you.

When to use them? I think never unless you have performance problems that warrants their use. They are very bad for grepability.



Related Topics



Leave a reply



Submit