About Me

My photo
I'm a colonist who has declared war on machines and intend to conquer them some day. You'll often find me deep in the trenches fighting off bugs and ugly defects in code. When I'm not tappity-tapping at my WMD (also, known as keyboard), you'll find me chatting with friends, reading comics or playing a PC game.

Friday, August 8, 2008

Alexandrescu to the rescue

(Reader Level : Intermediate)
(Knowledge assumptions : templates, std::vector, std::string)

I've recently taken a fancy to Andrei Alexandrescu's Modern C++ design. Its a fabulous book and anyone who is serious about becoming a good C++ programmer ought to read it. However, the book is not for the novice or the faint of heart. Someone on CodeGuru even suggested that the reader wear a helmet while reading this book so that his/her brain would not explode!

Now let me tell my story...
I was writing a string tokenizer in C++. The basic idea was to split a parse string into tokens using another string as the delimiter. The resultant token strings can be returned as a vector of strings.
std::vector<std::string> Tokenize( const std::string& str, const std::string& delimitStr )
{
std::vector<std::string> result;
//////Rest of the code goes here...//////////

return result;
}


Seems pretty sensible, right? Now here's the problem. What if I wanted to give the user the power to specify what kind of STL container he/she wanted to use. Perhaps, a list would be more pertinent, or maybe a deque. In order to do that the Tokenize() function needs to be templated. So here was my first attempt..
template<class Container>
Container Tokenize( const std::string& str, const std::string& tokenStr )
{
Container result;
//////Rest of the code goes here...//////////

return result;
}


Alright, that seems nice enough and the user would have to call this Tokenizer() routine as:
Tokenize<std::list<std::string> >( "breakmeintoathousandpieces", "e" );

Unfortunately, that's redundant because we know that the result is a container of string tokens. Furthermore, the user should not be given the opportunity to misuse the algorithm by specifying something other than std::string for the template argument. It should be fair to simply say:
Tokenize<std::list>( "breakmeintoathousandpieces", "e" );

That won't work however because then the container type would be incomplete. I was wondering how to resolve this problem when it hit me! The use of Template Template Parameters was illustrated for designing Policy classes in Modern C++ Design. It suited my purpose wonderfully!
This is what my revised Tokenizer() function looked like:
template< template<class> class Container >
Container<std::string> Tokenize( const std::string& str, const std::string& tokenStr )
{
Container<std::string> result;
//////Rest of the code goes here...//////////

return result;
}

This example was just to illustrate the use of template template parameters. As Alexandrescu so beautifully put it - "It is as if WidgetManager (the class he templated) were a little code generation engine, and you configure the ways in which it generates code."

If you really have a solid reason to tokenize anything complex, of course, I would recommend using Boost::Tokenizer.

No comments: