syntax highlight

Tuesday, 8 January 2013

Cool C++0X features XVI: Lambdas

Last time we created a device to sum an initializer list of ints, something like this:

void Add(initializer_list<int> lst) {
	int sum = 0;
	for (auto i = lst.begin(); i != lst.end(); ++i)
		sum += *i;

	cout << sum << "n";
}

And then we said this can be improved using some new C++0x wizardry to support actions other than adding. How would we do that? Easy, we need to decouple the iteration of the list from the operation logic. We can do something like this:


// Note how we don't care about the type of OP, just that
// it can be called (i.e. has an operator ())
template <class OP>
void do_something(OP op, int init, initializer_list<int> lst) {
	int sum = init;
	for (auto i = lst.begin(); i != lst.end(); ++i)
	{
		int x = *i;
		sum = op(sum, x);
	}

	cout << sum << "n";
}

struct Sum {
	int operator() (int a, int b)
	{
		return a + b;
	}
};

int main() {
	do_something(Sum(), 0, {1, 2, 3, 4});
	return 0;
}

We had to do some changes other than passing the operation-object into the do_something method; since the start value (zero) was hardcoded we had to remove it to really decouple the action from the iteration.

Other than creating a function object (which is the correct name for the object wrapping our operation) we don't see any strange changes, there's no C++0x there, but C++0x gives us a little tool which gives you the power of creating much simpler and nicer code, or to make the next maintainers' life a living hell. That's a discussion for other time though, now let's take a sneak preview a lambdas, the evolution of function objects:

int main() {
	auto f = [] (int a, int b){ return a+b; } ;
	do_something(f, 0, {1, 2, 3, 4});
	return 0;
}

Note that we didn't change anything on the method iterating the list, we just changed main! There's a lot to talk about lambdas, so this is only an intro to the subject. Next time we'll discuss the subtleties of the new syntax.

No comments:

Post a Comment