Working with C++0X/C++11: Lambdas – part 4 – using closures

In my last C++11 blog I talked about creating functions that takes a storage location by reference and return a function that takes a string input, parses it and stores the resulting value into the storage location. So we’re creating a function that returns a function.  The outer function takes a storage location. The inner function takes a string and stores it in the storage location.

So let’s create a function that takes an integer reference and a const string pointer, parses the string to an integer value, and stores it in the int. So far, so good. The tricky part is we’re going to return a function pointer to a function that takes the const string pointer as it’s argument. It looks like this;

.
    auto store_int = [](int& x) -> function < void (const char*) > { return [&x](const char* y){ stringstream(y) >> x; }; }; 
.

Let’s go over this in detail;

.
    auto store_int = 
.

I’m storing something (TBD but I know it’ll be a function pointer) in a variable named “store_int”. The next part is;

.
    [](int& x)
.

I’m storing a lambda that takes an int address and doesn’t capture any scope (it’s just a function that takes an int reference). Now we need to specify what this function returns;

 .
     -> function< void (const char*) >
.

… it returns a function pointer (the keyword function) and this function returns void and takes a const char pointer as an argument. In other words, I’m creating a function that takes an integer address as its argument, and this function then returns a function pointer to a function that takes a const char* as an argument and returns void. Now I just need to write the body of the lambda; This is going to be *another* lambda!

.
     { return [&x](const char* y) { stringstream(y) &gt&gt x; }; };
.

So I start the lambda body with an open curly brace, then I return a new lambda which I create in place; This inner lambda takes the reference to argument “x” (which was passed in as an argument to the outer lambda). Pass by reference allows it to modify the value in “x”; The inner lambda takes a const char pointer as its function argument. This argument comes from the argument list of the inner lambda I’m creating. Finally in the body of the inner lambda – I use stringstream to convert the string to an int through the right shift operator (it’s less error prone than atoi, and it works to convert to most data types, I use stringstream when I need to parse strings). So this is where the two function arguments actually connect, I parse the string and store it in the integer address. But these are provided in two separate function calls – the outer one and the inner one.

This is the trick – I create one function that takes a reference to the variable I want to store the command line parameter result in. This function encapsulates that integer reference up in another function that takes a char pointer. This is what gets returned. The integer reference is totally hidden from the outside. When you call this function the string argument gets parsed and stored in the referenced integer. This is a closure. Sometime after I create this function, I can call it with a const char* argument, and that string will get converted to an integer and stored in the integer address that was passed in when I created the closure.

I’ll post how you’d use this in a more complete implementation in my next post. That will make the magic of closures much more obvious. But to wrap up, let’s look at using what we created above;

.
    int myInt; // create an integer

    // pass the integer to store_int
    auto mfunc = store_int(myInt);

    // mfunc is a function taking a const char*
    // the reference to myInt is hidden inside mfunc

    mfunc("4"); // use it, the string gets parsed
    // myInt gets set to 4 
.

So we’ve used closures to hide a reference to a variable and its type. Next time we’ll use this not only to hide variable address and type information, but to hide behavior modifications as well.

This entry was posted in C++0X/C++11, Code. Bookmark the permalink.