Channels ▼

Mark Nelson

Dr. Dobb's Bloggers

Visual Studio 11: The Early Release

March 15, 2012

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.

Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 


Video