[Updated Apr 3 to note automatic deduction of return type.]
The ISO C++ committee met in Bellevue, WA, USA on February 24 to March 1, 2008. Here’s a quick summary of what we did (with links to the relevant papers to read for more details), and information about upcoming meetings.
Lambda functions and closures (N2550)
For me, easily the biggest news of the meeting was that we voted lambda functions and closures into C++0x. I think this will make STL algorithms an order of magnitude more usable, and it will be a great boon to concurrent code where it’s important to be able to conveniently pass around a piece of code like an object, to be invoked wherever the program sees fit (e.g., on a worker thread).
C++ has always supported this via function objects, and lambdas/closures are merely syntactic sugar for writing function object. But, though “merely” a convenience, they are an incredibly powerful convenience for many reasons, including that they can be written right at the point of use instead of somewhere far away.
Example: Write collection to console
For example, let’s say you want to write each of a collection of Widgets to the console.
// Writing a collection to cout, in today’s C++, option 1:
for( vector<Widget>::iterator i = w.begin(); i != w.end(); ++i )
cout << *i << ” “;
Or we can leverage that C++ already has a special-purpose ostream_iterator type that does what we want:
// Writing a collection to cout, in today’s C++, option 2:
copy( w.begin(), w.end(),
ostream_iterator<const Widget>( cout, ” ” ) );
In C++0x, just use a lambda that writes the right function object on the fly:
// Writing a collection to cout, in C++0x:
for_each( w.begin(), w.end(),
[]( const Widget& w ) { cout << w << ” “; } );
(Usability note: The lambda version was the only one I wrote correctly the first time as I tried these examples on compilers to check them. ‘Nuff said. <tease type=”shameless”> Yes, that means I tried it on a compiler. No, I’m not making any product feature announcements about VC++ version 10. At least not right now. </tease>)
Example: Find element with Weight() > 100
For another example, let’s say you want to find an element of a collection of Widgets whose weight is greater than 100. Here’s what you might write today:
// Calling find_if using a functor, in today’s C++:
// outside the function, at namespace scope
class GreaterThan {
int weight;
public:
GreaterThan( int weight_ )
: weight(weight_) { }
bool operator()( const Widget& w ) {
return w.Weight() > weight;
}
};
// at point of use
find_if( w.begin(), w.end(), GreaterThan(100) );
At this point some people will point out that (a) we have C++98 standard binder helpers like bind2nd or (b) that we have Boost’s bind and lambda libraries. They don’t really help much here, at least not if you’re interested in having the code be readable and maintainable. If you doubt, try and see.
In C++0x, you can just write:
// Calling find_if using a lambda, in C++0x:
find_if( w.begin(), w.end(),
[]( Widget& w ) { return w.Weight() > 100; } );
Ah. Much better.
Most algorithms are loops… hmm…
In fact, every loop-like algorithm is now usable as a loop. Quick examples using std::for_each and std::transform:
for_each( v.begin(), v.end(), []( Widget& w )
{
…
… use or modify w …
…
} );
transform( v.begin(), v.end(), output.begin(), []( Widget& w )
{
…
return SomeResultCalculatedFrom( w );
} );
Hmm. Who knows: As C++0x lambdas start to be supported in upcoming compilers, we may start getting more used to seeing “});” as the end of a loop body.
Concurrency teaser
Finally, want to pass a piece of code to be executed on a thread pool without tediously having to define a functor class out at namespace scope? Do it directly:
// Passing work to a thread pool, in C++0x:
mypool.run( [] { cout << “Hello there (from the pool)”; } );
Gnarly.
Other approved features
- N2535 Namespace associations (inline namespace)
- N2540 Inheriting constructors
- N2541 New function declarator syntax
- N2543 STL singly linked lists (forward_list)
- N2544 Unrestricted unions
- N2546 Removal of auto as a storage-class specifier
- N2551 Variadic template versions of std::min, std::max, and std::minmax
- N2554 Scoped allocator model
- N2525 Allocator-specific swap and move behavior
- N2547 Allow lock-free atomic<T> in signal handlers
- N2555 Extended variadic template template parameters
- N2559 Nesting exceptions (aka wrapped exceptions)
Next Meetings
Here are the next meetings of the ISO C++ standards committee, with links to meeting information where available.
- June 8-14, 2008: Sophia Antipolis, France
- September 14-20, 2008: San Francisco Bay area, California, USA
The meetings are public, and if you’re in the area please feel free to drop by.