Templates and Streams; the perfect couple

Recently I’ve been doing some work templatifying my two I/O classes, and from that have come to the conclusion that templates and streams make for the ultimate generic programming tool. Previously I had a load of old duplicate bloat code in these classes, that was all removed and replaced by one templated member function, and two specialised template functions from it, and best of all since this code is now able to take external streams as input/output sources, it means that I no longer have one code path for handing files, and another code path for serialising to memory. Instead I just pass an fstream when working with files, and a stringstream when I want to serialise to/from memory, simple!

One of the best changes the templates and streams has made is to my tryParse function. Previously there were a load of these, each handling a different variable type using old C functions. Now the function has been replaced by a single templated function, and a stringstream. If you try and tryParse a type a stringstream can’t handle, it just doesn’t compile, best of all is that you can still expand the function using template specialisation if you want to tryParse to your own custom types.

//! Try and parse a string to another type
//! \return true if the conversion was ok, false otherwise
template <typename T>
bool tryParse(
	const std::string &str, //!< String to convert
	T &out                  //!< Output variable
	std::stringstream sstream;
	sstream.exceptions(std::ios::failbit | std::ios::badbit);
	sstream << str;
	try { sstream >> out; }
	catch(std::exception&) { return false; }
	return true;

I actually worked out the total number of lines of code before, and after my changes. The results are below:

Reader      - 183    (header)  1,042 (source)
Writer      - 209    (header)    839 (source)
TryParse    - 50     (header)    115 (source)
Total       - 2,438

Reader      - 271    (header)    351 (source)
Writer      - 226    (header)    245 (source)
TryParse    - 30     (header)      0 (source)
Total       - 1,123

Quite impressive :) (Although I did cheat slightly since the new reader and writer have a macro which removes a lot of code repetition from the header, it probably saves ~39 lines of code from each class, so ~78 in all. Still that would only make it 1,201 lines of code which is still a huge saving for something that has more functionality with less code).

As with everything with stringstreams, this sacrifices performance for reduced code complexity. If your code is performance critical I’d advise using the C-style conversion functions rather than a stringstream.

comments powered by Disqus