Auto Types and Range-Based For Statements in C++11
Putting It to Use
Although it didn't really cut down on my code size in a big way, I first made use of the range-based for in the loop that reads in the data from the Scrabble dictionary. My new version of the loop is shown here:
for ( const std::string &s : std::istream_iterator<std::string>( data ) )
{
std::string temp = s;
std::sort(temp.begin(), temp.end() );
counts[temp]++;
words.insert( std::make_pair(temp,s) );
}
More Insights
White Papers
More >>Reports
- Informed CIO: SDN and Server Virtualization on a Collision Course
- InformationWeek 2013 Strategic Security Survey
Webcasts
- The Untapped Potential of Mobile Apps for Commercial Customers
- Agile for Safety Critical Systems: Project Management Practices
The only big improvement here is that I was able to declare my string variable on first use, which is always my preference.
However, looking at this code, you might be wondering how it compiles. After all, the istream_iterator doesn't have begin() or end() member functions.
That's correct, and the reason it works is that I added a couple of convenience functions to my program that enable the use of this iterator type with the range-based for:
template<class T>
std::istream_iterator<T> begin(std::istream_iterator<T> &ii_stream)
{
return ii_stream;
}
template<class T>
std::istream_iterator<T> end(std::istream_iterator<T> &ii_stream)
{
return std::istream_iterator<T>();
}
I made use of a similar set of template functions to enable the use of the new for statement in my final output statement. I now iterate over the discovered members of the anagram family with two easy-to-read lines:
for ( const auto &map_entry : words.equal_range( ii->first ) )
std::cout << map_entry.second << " ";
Compare this to the TR1 code that does the same thing, and I think you will see the real value of both auto and range-based for.
Iterating over the values returned from a multimap is a common task, enabled by these convenient template functions:
template<class ITERATOR>
ITERATOR begin( std::pair<ITERATOR,ITERATOR> &range )
{
return range.first;
}
template<class ITERATOR>
ITERATOR end( std::pair<ITERATOR,ITERATOR> &range )
{
return range.second;
}
When I first implemented the functions for my C++11 program, I was halfway expecting to find that this functionality had already been added to the standard library — they really make a big improvement for a small investment. But no, I couldn't find them, so we will be using our own versions for the time being.
The Final Product
My much-improved anagram finder is shown below. In addition to the use of range-based for and auto type declarations, I changed the way I find the maximum element in the container. Now that lambdas are part of the language, there is no excuse for not using the standard library algorithms, and this code gives an illustration of how that works as well.
#include <iostream>
#include <fstream>
#include <string>
#include <iterator>
#include <algorithm>
#include <unordered_map>
template<class ITERATOR>
ITERATOR begin( std::pair<ITERATOR,ITERATOR> &range )
{
return range.first;
}
template<class ITERATOR>
ITERATOR end( std::pair<ITERATOR,ITERATOR> &range )
{
return range.second;
}
template<class T>
std::istream_iterator<T> begin(std::istream_iterator<T> &ii_stream)
{
return ii_stream;
}
template<class T>
std::istream_iterator<T> end(std::istream_iterator<T> &ii_stream)
{
return std::istream_iterator<T>();
}
int main(int argc, char* argv[])
{
std::ifstream data( "sowpods.txt" );
std::unordered_map<std::string,int> counts;
std::unordered_multimap<std::string,std::string> words;
for ( const std::string &s : std::istream_iterator<std::string>( data ) )
{
std::string temp = s;
std::sort(temp.begin(), temp.end() );
counts[temp]++;
words.insert( std::make_pair(temp,s) );
}
auto ii = std::max_element( counts.begin(),
counts.end(),
[](const std::pair<std::string,int> &v1,
const std::pair<std::string,int> &v2)
{
return v1.second < v2.second;
}
);
std::cout << "The maximum anagram family has " << ii->second << " members:\n";
for ( const auto &map_entry : words.equal_range( ii->first ) )
std::cout << map_entry.second << " ";
std::cout << std::endl;
return 0;
}
Anagram Finder in C++11
If I move the four convenience functions into a utility header file, I think you'll agree that the new version of the code implements my algorithm in a very clean and concise way. The new language improvements make a huge difference in readability and convenience.
Of course, these two features are just one small part of a huge new standard, but for right now, they are the ones I turn to the most. How about you? Let me know!

