//
you're reading...
C++, Programming Issues/Tips

Using Boost Lambda Expression – Performing Iterations on Vector Elements.

1. Introduction.

1.1 When performing iterations and transformations on STL containers, the Boost Lambda Expressions can be a useful alternative to using regular function class objects.

1.2 For those not familiar with the Boost Lambda Library (BLL), please refer to their library web site for full documentation.

1.3 From the next section onwards, 2 code samples will be listed. Both samples will demonstrate action being taken on the items of a vector via iteration. The difference between them will then be briefly discussed.

2. Vector Iteration : Using Typical Functors.

2.1 Consider the following set of routines :

struct add_two_numbers : std::binary_function<int, int, int>
{
	int operator() (const int& lhs, const int& rhs) const 
	{
		return lhs + rhs;
	}
};

struct display_number : std::unary_function<int, void>
{
	void operator() (const int& num)
	{
		std::cout << num << std::endl;
	}
};

void IterateVectorUsingFunctors()
{
	// Define a integer vector.
	std::vector<int> vecInt;

	// Insert values into this vector.
	for (int i = 0; i < 10; i++)
	{
		vecInt.push_back(i);
	}

	// Increment every value in the vector
	// by 20.
	std::transform
	(
		vecInt.begin(), 
		vecInt.end(),
		vecInt.begin(),
		bind1st(add_two_numbers(), 20)
	);

	// Display each value in the vector.
	std::for_each
	(
		vecInt.begin(), 
		vecInt.end(), 
		display_number()
	);	
}

The following is a summary of the set of codes above :

  • add_two_numbers is a functor class based on the std::binary_function class.
  • It takes 2 numbers as parameter and returns their sum.
  • display_number is std::unary_function based functor class.
  • It displays an input number on the console.
  • IterateVectorUsingFunctors() is the main function that defines an integer vector and fills it with initial values.
  • It then increments the values in the vector by 20 using std::transform() and the add_two_numbers functor.
  • It finally displays all the current values inside the vector by using std::for_each() and the display_number functor.

2.2 The routines are simple and easily comprehended by C++ developers familiar with STL vectors and algorithms.

2.3 When IterateVectorUsingFunctors() is run, the console output will be as follows :

20
21
22
23
24
25
26
27
28
29

3. Vector Iteration : Using Lambda Expressions.

3.1 Next have a look at the following code :

#include "stdafx.h"
#include <boost/lambda/lambda.hpp>
#include <boost/ref.hpp>
#include <iostream>
#include <vector>

using namespace boost;
using namespace boost::lambda;

void IterateVectorUsingLambdaExpression()
{
	// Define a integer vector.
	std::vector<int> vecInt;

	// Insert values into this vector.
	for (int i = 0; i < 10; i++)
	{
		vecInt.push_back(i);
	}

	// Increment every value in the vector
	// by 20.		
	std::for_each
	(
		vecInt.begin(), 
		vecInt.end(), 
		_1 += 20
	);

	// Display each value in the vector.
	std::for_each
	(
		vecInt.begin(), 
		vecInt.end(), 
		std::cout << _1 << '\n'
	);	
}

The code above uses the Boost Lambda Library (BLL). To use this library, you would of course need to first have the boost library installed on your system and have your Visual Studio C++ Project’s “Additional Include Directories” setting point to your boost library folder.

The following is a summary of the code above :

  • The intention of the IterateVectorUsingLambdaExpression() function is the same as that of IterateVectorUsingFunctors() which we saw in point 2.1.
  • However, this time, the act of incrementing every value in the vector by 20 is accomplished using a Lambda expression :
_1 += 20
  • This lambda expression essentially defines a small unnamed function object in which “_1” is the first parameter.
  • As each iteration of std::for_each() is performed, this unnamed function is called with each vector element being the actual argument passed by reference as per boost documentation :

When an actual argument is supplied for a placeholder, the parameter passing mode is always by reference.

  • Hence each vector item gets to be incremented by a value of 20.
  • After that, another std::for_each() loop is performed. This time, the Lambda expression displays each vector item on the console.

3.2 When IterateVectorUsingLambdaExpression() is run the following will be the console output :

20
21
22
23
24
25
26
27
28
29

which is exactly the same as the output from IterateVectorUsingFunctors().

3.3 A special thing about Lambda expressions is the direct use of objects and constructs within scope, e.g. :

void IterateVectorUsingLambdaExpression2(int iIncrement)
{
	// Define a integer vector.
	std::vector<int> vecInt;

	// Insert values into this vector.
	for (int i = 0; i < 10; i++)
	{
		vecInt.push_back(i);
	}

	// Increment every value in the vector
	// by the current value of iIncrement.
	std::for_each
	(
		vecInt.begin(), 
		vecInt.end(), 
		_1 += iIncrement
	);

	// Display each value in the vector with a heading message.
	char* lpszMessage = "Vector element : ";

	std::for_each
	(
		vecInt.begin(), 
		vecInt.end(), 
		std::cout << constant(lpszMessage) << _1 << '\n'
	);	
}

The following is a summary of the code above :

  • In the first std::for_each() loop, each vector item is incremented by whatever current value “iIncrement” holds. It need not be a constant value.
  • In the second std::for_each() loop, as each vector item is displayed, a heading message is displayed. This message is the string stored in “lpszMessage” which is treated as a constant in the Lambda expression.

3.4 A use of the IterateVectorUsingLambdaExpression2() function like the following :

IterateVectorUsingLambdaExpression2(3);

will produce the following console output :

Vector element : 3
Vector element : 4
Vector element : 5
Vector element : 6
Vector element : 7
Vector element : 8
Vector element : 9
Vector element : 10
Vector element : 11
Vector element : 12

4. In Conclusion.

4.1 When we use functors to perform actions on a STL container, the function class has to be defined somewhere of course.

4.2 When we use functors, we sometimes have to modify their usage by using adapters like bind1st(). This can add to complexity.

4.3 Compared with the use of function objects, the example use of Lambda expressions as presented in this article certainly looked much simpler.

4.4 Indeed, the use of Lambda expressions can at times produce simpler code viz those required by function class objects albeit this is not always guaranteed.

4.5 However, function classes are by nature re-usable and can be made generic by declaring them template-based. This is their main advantage over the Lambda expressions.

Advertisements

About Lim Bio Liong

I've been in software development for nearly 20 years specializing in C , COM and C#. It's truly an exicting time we live in, with so much resources at our disposal to gain and share knowledge. I hope my blog will serve a small part in this global knowledge sharing network. For many years now I've been deeply involved with C development work. However since circa 2010, my current work has required me to use more and more on C# with a particular focus on COM interop. I've also written several articles for CodeProject. However, in recent years I've concentrated my time more on helping others in the MSDN forums. Please feel free to leave a comment whenever you have any constructive criticism over any of my blog posts.

Discussion

No comments yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: