Visual Studio 11: The Early Release
Of course, just like with OOP, you need to take some care with template programming. Generic programming can't be beat when it makes sense, but programmers have a particularly strong susceptibility to pro-innovation bias.
Using the Algorithms Library
Again, prodded by changing styles in the C++ world, my next step is to use a standard library algorithm to do the work. We're told over and over that turning to the algorithms library allows you to use code that has been optimized to the n-th degree by the clever library teams.
In order to make this work, I have to call an algorithm with a predicate functor, seen below as class sorted_not_equal. Note also that I can't use the logical function for this, which would be copy_if(). Why not? The committee forgot to put it in back in 1998, 2003, and 2005, a mistake that was fortunately remedied in C++11. So I have to use the inverse function, remove_copy_if(), and invert the logical sense of my functor:
class sorted_not_equal {
std::string str;
public :
sorted_not_equal( const std::string & test )
{
str = test;
sort( str.begin(), str.end() );
}
bool operator()( std::string test )
{
sort( test.begin(), test.end() );
return ( str != test );
}
};
template<typename INPUT_ITERATOR, typename OUTPUT_ITERATOR>
void find_matches( std::string rack,
INPUT_ITERATOR ii,
INPUT_ITERATOR jj,
OUTPUT_ITERATOR kk )
{
std::sort( rack.begin(), rack.end() );
std::remove_copy_if( ii, jj, kk, sorted_not_equal( rack ) );
}
int main(int argc, char* argv[])
{
std::ifstream sowpods( "sowpods.txt" );
find_matches( "etaionsr",
std::istream_iterator<std::string>( sowpods ),
std::istream_iterator<std::string>(),
std::ostream_iterator<std::string>(std::cout, "\n" ) );
return 0;
}
Functors Not So Hot
So this new approach is supposed to soup up my code by taking advantage of the algorithms that come with the standard library. But if you look at the code people have been writing for the past 10 years, you'll find that this style is pretty common in textbooks and magazine articles, but no so much in the real world.
Why not? Well, it's pretty obvious. The generic algorithms in the library need lots of predicate glue to make them useful, and the work to create these predicates is just a pain. My code is almost twice as long, and the functionality that took two lines of code earlier is now bloated into a complete class definition. It pollutes my namespace, takes up a lot of space, and has to be defined somewhere distant from where it is actually used. Not a win.
This is obviously a problem when you look at the history of Linux, C, and C++. An entire family of technologies and infrastructure was developed with the implicit goal of reducing the number of keystrokes programmers had to enter. (I'm kidding, but only somewhat.) Functors are a step in the wrong direction.
Lambda to the Rescue
So it is with much relief that C++11 delivers lambdas, which allow us to write short sweet predicates exactly where we need them, as shown in this C++11 version of the example:
template<typename INPUT_ITERATOR, typename OUTPUT_ITERATOR>
void find_matches( std::string rack,
INPUT_ITERATOR ii,
INPUT_ITERATOR jj,
OUTPUT_ITERATOR kk )
{
std::sort( rack.begin(), rack.end() );
std::copy_if( ii, jj, kk,
[&rack](std::string str) ->bool
{
std::sort( str.begin(), str.end() );
return rack == str;
}
);
}
int main(int argc, char* argv[])
{
std::ifstream sowpods( "sowpods.txt" );
find_matches( "etaionsr",
std::istream_iterator<std::string>( sowpods ),
std::istream_iterator<std::string>(),
std::ostream_iterator<std::string>(std::cout, "\n" ) );
return 0;
}
Yes, I now have to get used to a new syntax for writing lambda functions — I think that was unavoidable. But my lambda function is short, it is quite easy to see exactly what it is doing, and it replaces a gangly and awkward functor class.
Best of all, I use the lambda exactly where I need it — as the predicate parameter to an algorithm used in the standard library. Locality rules.
Using Lambdas
Visual C++ 11 provides a great framework for experimenting with lambdas, as they are supporting the 1.1 definition that was ratified as part of the standard. If you want the gory details, I believe the working group's proposal has essentially the same wording that went into the standard. For a detailed tutorial, Herb Sutter's talk can't be beat.

