Solarian Programmer

My programming ramblings

C++14 lambda tutorial

Posted on August 28, 2014 by Sol

The last iteration of C++, C++14 was approved this month. C++14 brings a few much anticipated changes to the C++11 standard, like allowing auto to be used as the return type of a function, or generic lambdas - the subject of this article.

Lambdas, in C++, were introduced by the C++11 standard. They were meant to let the coder write short, anonymous functions, that could be used instead of a function object, avoiding the need to create a separate class and a function definition. Here is a typical example of C++11 lambda usage, that returns the square of a number:

1 int result = [](int input) { return input * input; }(10);
2 cout << result << endl;

If you need to reuse the same piece of code in more than one place, you can save the function in a variable:

1 auto func = [](int input) { return input * input; };
2 
3 // first use
4 std::cout << func(10) << std::endl;
5 
6 // second use
7 std::cout << func(23) << std::endl;

Can you see the problem with the above code ? It can be used only for integers. What if, we want to use the same lambda for a double or for a complex number ? Say that we want to be able to write something like this:

1 // square of an int
2 std::cout << func(10) << std::endl;
3 
4 // square of a double
5 std::cout << func(2.345) << std::endl;
6 
7 // square of a complex number
8 std::cout << func(std::complex<double>(3, -2)) << std::endl;

We could obviously use a function template:

1 template <typename T>
2 T func(T z) {
3     return z * z;
4 }

However, this is not the solution we are looking for in the context of this article, the above is a named, global function,

The C++14 standard introduced the concept of generalized lambda, basically we are allowed to use auto for the parameter types of a lambda expression. We could write a shorter and, in a way, more elegant solution now:

1 auto func = [](auto input) { return input * input; };

Here is a complete program that exemplifies the above:

 1 #include<iostream>
 2 #include<complex>
 3 
 4 int main() {
 5     // Store a generalized lambda, that squares a number, in a variable
 6     auto func = [](auto input) { return input * input; };
 7 
 8     // Usage examples:
 9     // square of an int
10     std::cout << func(10) << std::endl;
11 
12     // square of a double
13     std::cout << func(2.345) << std::endl;
14 
15     // square of a complex number
16     std::cout << func(std::complex<double>(3, -2)) << std::endl;
17 
18     return 0;
19 }

The above code can be compiled with any modern C++ compiler, like GCC 4.9.x or Clang. Here is the result of compiling and running the code with GCC and Clang on OS X:

 1 $ clang++ -std=c++1y -pedantic -Wall -stdlib=libc++ test_01.cpp -o test_01
 2 $ ./test_01
 3 100
 4 5.49903
 5 (5,-12)
 6 $ g++-4.9.1 -std=c++14 -pedantic -Wall test_01.cpp -o test_01
 7 $ ./test_01
 8 100
 9 5.49903
10 (5,-12)
11 $

However, the generic lambda shines in combination with STL. Suppose that you want to sort a vector in decreasing order. Using a generic lambda, we can write:

1 std::sort(V.begin(), V.end(), [](auto i, auto j) { return (i > j); });

Here is a complete example of sorting a vector, of ten integers, in decreasing order, using generic lambda and the STL:

 1 #include<iostream>
 2 #include<vector>
 3 #include<numeric>
 4 #include<algorithm>
 5 
 6 int main() {
 7     std::vector<int> V(10);
 8     
 9     // Use std::iota to create a sequence of integers 0, 1, ...
10     std::iota(V.begin(), V.end(), 1);
11     
12     // Print the unsorted data using std::for_each and a lambda
13     std::cout << "Original data" << std::endl;
14     std::for_each(V.begin(), V.end(), [](auto i) { std::cout << i << " "; });
15     std::cout << std::endl;
16 
17     // Sort the data using std::sort and a lambda
18     std::sort(V.begin(), V.end(), [](auto i, auto j) { return (i > j); });
19     
20     // Print the sorted data using std::for_each and a lambda
21     std::cout << "Sorted data" << std::endl;
22     std::for_each(V.begin(), V.end(), [](auto i) { std::cout << i << " "; });
23     std::cout << std::endl;
24 
25     return 0;
26 }

This is the result of running the above code on my machine:

1 $ g++-4.9.1 -std=c++14 -pedantic -Wall test_02.cpp -o test_02
2 $ ./test_02
3 Original data
4 1 2 3 4 5 6 7 8 9 10
5 Sorted data
6 10 9 8 7 6 5 4 3 2 1
7 $

If you are interested to learn more about the new C++11 syntax I would recommend reading The C++ Programming Language by Bjarne Stroustrup.

or, Professional C++ by M. Gregoire, N. A. Solter, S. J. Kleper 2nd edition:

comments powered by Disqus