Fun with functions presents a modern, functional programming look on functions within C++/C++11. It shows what is possible with function, how it can be applied and how it ties into the STL library. I've very much tried to explain things by example. This information should give you a broader look on how functions can be used and let you have more fun with them. It is aimed towards intermediate to advanced level programmers, for a basic introduction to functions read http://www.dreaminco...-i-the-basics/.

The tutorial will cover the following topics.

Function pointers

Anonymous/lambda functions

Partial function application

Higher order functions

Higher order functions in the STL

Templating our functions

Creating new loop constructs

Variadic template functions

All code snippets have have been compiled with g++ 4.6.1 (g++ -std=c++0x file) and should be valid c++11. The fully working example programs are at the bottom.

1) Function pointers.

Function pointers have been a part of C++ since the beginning, in fact they have been a part of C from the beginning. But their interface has always been cumbersome.

An example of a classic C function pointer, feel free to skip to the new:

The old:

int foo(double) {}
int (*foo_ptr)(double) = &foo;

Now you can call the function through the pointer like this foo_ptr(5.0);

This represents 3 ways to to create a function pointer without knowing anything about it's type. The first one is the simplest and the result the same as the second one. The third one explicitly wraps it in a std::function wrapper.

For member functions it is a little more difficult. &A::foo is actually the old function pointer type with it's incredibly weird call syntax. We can however convert it to a regular function that takes it's object as a first argument like this:

A a;
auto call_foo2 = std::mem_fn(&A::foo);
call_foo(a, 5.0);

a may also be an A*.

Or use bind as explained in Partial function application.

I make use of the auto keyword extensively throughout the tutorial. And when I call something a function in this tutorial it can have many different types. Including but not limited to a function pointers, std::function objects, bind objects (see partial function application) or functors you defined yourself.

Don't confuse using auto as not using strong typing. The compiler knows exactly what type auto is at compile time.

2) Anonymous/lambda functions

Anonymous functions, also called lambda functions are a new c++11 functions with no name that can be created everywhere. For example:

Notice the [&sum], this means that we make the sum variable available to the lambda function by reference. We can also make any combination of variables available to the the lambda function. This table summarizes how it would work.

[]: no variables defined. Attempting to use any external variables in the lambda is an error.
[x, &y]: x is captured by value, y is captured by reference
[&]: any external variable is implicitly captured by reference if used
[=]: any external variable is implicitly captured by value if used
[&, x]: x is explicitly captured by value. Other variables will be captured by reference
[=, &z]: z is explicitly captured by reference. Other variables will be captured by value

This is a powerful tool, for example, want the sum of the variables in an array or any other container or just print it.

Can you see what is happening, for_each will call a function for every element, we pass it a lambda function that has access to the sum variable and increments it. Can you guess the line that will multiply all the elements ?

You can also call a lambda recursively but it does require a little trick. Take the following factorial function as an example (fact(n) = n! = n * (n-1) * (n-2) * ... * 1).

Bind, by default, always copies arguments by value even if the function takes references. But you can override this behavior by wrapping your arguments with std::ref or std::cref (constant reference). Beware however that if you do so, that you make the free functions dependent on the variables you pass by reference, this can hurt you silently when the variable goes out of scope before the bind object. The same is true when you use pointers, but bind does work excellently in combination with smart pointers.

A special form of binding is binding a member function to an object to create a free function. Remember our example:

class A {
public:
int foo(double) {}
};

Suppose we already have an object of type A and want a free function, then.

A a;
auto free_foo = std::bind(&A::foo, a, std::placeholders::_1);

The next concept is transforming a function called on an object to a function that takes the object it would have been called on as a parameter. This can be very useful. Suppose you have a vector of Objects of type A. And A has a member function foo.

std::vector<A> vector_of_A;

Now I want to call foo on every object in the vector with for_each but I have a problem. For_each takes a function that takes an object of type A, but A::foo doesn't take an object of type A it is called on an object of type A. We can solve this with std::bind or the mem_fn wrappers we have seen already.

These 2 statements transform a function that is called on an object to a function that takes the object it is supposed to be called on as a parameter.

4) Higher order function

Higher order functions is just a term used for functions that take other functions as a parameter and/or return a function. If you are familiar with the stl, then you've probably already used them. The for_each/find_if/sort_by,... they all take a function as a parameter. So let's make our own.

Suppose we want to make a sum, sum_of_square, sum_of_cubes function, but we are lazy. We have this sum function:

Note that our suma function looks very much like the stl functions for_each, find_if, etc in the algorithm header, if you ever wondered how it's done, this is how. The stl versions will work with any type though, not just a vector of doubles, we will deal with this in "6) Templating our functions".

Ok we can now calculate those sums, but I want to make functions to calculate those sums, no problem:

We cannot just return g(f()) as it is not immediately obvious to the compiler that the types match. But what we can do is return a new lambda function that applies the functions the way we want them to. See the [=], this gives the lambda function access to the functions f,g.

Also containers like map/set/multimap/multiset take a function as a template type parameter and optional parameter. Many containers also have higher order member functions not mentioned here.

These in combination with the convenience of lambda functions can be powerful tools to make your code shorter, faster and more to the point. See the programs at the bottom to see an example of the stl at work.

6) Templating our functions

You probably noticed that the functions in the algorithm header seem to work with any type, container or function you throw at it and you are wondering if your functions can do the same. Well let's find out. Let's create our own for_each function. Looking back at the sum example, you should be able to make one that works for just ints for example, it's a good exercise to try for yourself.

We use the begin pointer as the current pointer, as it already is a copy and an additional copy would be wasteful.

If we wanted a for_each function for vectors of doubles, we would have to write a function that is exactly the same except int would be double. If we used a std::list, then that wouldn't change anything either, just replace all std::vector with std::list and it will work. For this C++ offers templates.

So let's try to make it container agnostic first. To do this we replace std::vector<int>::iterator with a template parameter:

This behaves almost the same like any ordinary for loop. The same variables external variables are available (see [&]), And the current element in the container will be accessible through x. It is almost equivalent to:

for(auto it = vect.begin(), it != vect.end(), ++it) {
int& x = *it;
}

And the very similar to the new c++11 for each loop construct:

for (int& x: vect) {
//x will loop over all members of vect
}

I say almost and very similar because control statements like continue and break are not available. A return statement in the lambda function will function as a continue but there is no break.

This looping using a lambda function however has far reaching consequences because we can easily make our own for_each like functions and thus create new kinds of loops.

For example, we want a loop that loops over every odd member of any container. Then we could write something like this:

So what are the return true/false and the strange if (!f(i)) return; in the generate_primes doing there. Well we need a way to exit the loop, traditional control statements like break and continue don't work because we are not technically in a loop. The solution I've used here is to make the function passed to generate prime a boolean function where true means continue and false means stop.

Alternatively we could pass an additional predicate function to generate_primes like we did in for_each_if.

Try to implement every looping construct let's say ruby supports, I'm sure it can be done.

Variadic templates allow functions to take any number of variables as a variable/type pack. This is perhaps best explained through an example.

So let's create a simple sum function, that takes any number of parameters, so we want to be able to call it like this:

sum(1, 2, 3, 4)
sum(1, 3)

And any other number of parameters.

We can create a function declaration that can take any number of parameters like this

template <class... Nrs>
double sum(Nrs... nrs);

The problem is that we cannot simply iterate over the nrs (not directly, see later). We can however send it to another function, but then we would have the same problem there. What we can do is slightly change the declaration so we get one parameter separately.

This is a recursive definition of a sum, the sum of all elements is the first element + the sum of the remaining elements. This almost works, but when we try to compile it we get an error that no definition for sum() exists. What happens is that this recursion continues until the last element, after that the tail is empty and it tries to call sum with no parameters. So the solution, create a function sum with no parameters.

The problem with this is that the variadic template paramter pack must be homogeneous. It is with regret that the Standard Committee didn't add the ability to iterate through a variadic parameter pack. I would've added variadic template support for the new range-for loop and overloaded the subscript operator to access the nth element. This means that we wouldn't have to use recursion. For example:

True. Although this is really easy for a compiler to optimize. I did a test g++ -std=c++0x -O3 test.cpp (gcc 4.7) with your example above and the code generated was identical. And yes I made certain the code was actually executed. Nevertheless I edited the tutorial, better to be explicit than to rely on compiler optimizations that may or may not be active.

The problem with this is that the variadic template paramter pack must be homogeneous. It is with regret that the Standard Committee didn't add the ability to iterate through a variadic parameter pack. I would've added variadic template support for the new range-for loop and overloaded the subscript operator to access the nth element. This means that we wouldn't have to use recursion. For example:

I'm certainly aware that for that the types must be homogeneous or at least implicitly convertible to the type of the container. But I see I forgot to make a note of it.

I can certainly understand your point, you can sort of do the auto i = params[n];, by using params... to create a tuple (auto tuple = std::make_tuple(params...)) and using std::get<n>(tuple). But n of course must be known at compile time.

I can see your suggestion work, but this would require language support, you can not actually write it within the current C++11 language. You would have to strictly keep to auto type deduction for variables and template type deduction for variables/functions you want to assign/call with something from a heterogeneous parameter pack. But I too would have much preferred this over enforcing recursive solutions. At the current rate, it might be in C++24 .

You can sort of work around it by using a recursive expand function that calls an overloaded function with the first parameter each time as demonstrated here http://www.dreaminco...arameter-idiom/ .

Thank you for some excellent suggestions. If you have the time, I could use some suggestions on what really should be and shouldn't be included in this tutorial.

This post has been edited by Karel-Lodewijk: 19 February 2012 - 08:37 AM