T B H P N

Generic Programming with Templates

Synopsis:

Templates support building parameterized types and functions that accept an unspecified type which gets resolved only when an application instantiates the code with a concrete type. Parameterized code will accept, without compilation error, arbitrary calls on instances of the template type. When an application instantiates the parameterized code with a concrete type compilation of the instantiated code succeeds if the type supports specified operations, else it fails.

So there are two C++ template compilation phases:

  1. Compilation of the template library code does a syntax check to identify known errors. No object code is generated since the type of the template parameter is not specified.
  2. Compilation of the instantiated application code generates an object file if instantiated syntax is correct, otherwise it fails.
This lazy syntax checking is very useful. C# and Java generics do eagar type checking so many operations that would succeed for useful types are not allowed because the compiler can't ensure that they will succeed.

An implication of this lasy compilation is that all of the template definition code must go in a header file, because the application that uses the template definition has to see all of it's code to compile successfully, and it gets that only by including a header file.

An Example:

The Convert<T> class converts any type to and from strings, provided they have appropriate insertion and extraction operators. It works for all of the native numerical types without writing any additional code.

Template Example Code - TemplatesIntro.h
template<typename T>
class Convert
{
public:
  virtual ~Convert() {}
  static std::string toString(const T& t);
  static T fromString(const std::string& str);
  static std::string id(const T& t);
};
/*----< serialize t to a std::string >-----------------------------*/
/*
* Assumes that T defines an insertion operator.
*/
template<typename T>
std::string Convert<T>::toString(const T& t)
{
  std::ostringstream out;
  out << *const_cast(&t);
  return out.str();
}
/*----< create an instance of T from a std::string >---------------*/
/*
* Assumes that T defines an extraction operator.
* To succeed str must be created from Convert::toString(const T& t).
*/
template<typename T>
T Convert<T>::fromString(const std::string& str)
{
  std::istringstream in(str);
  T value;
  in >> value;    // istringstream extraction provides the conversion
  return value;
}
/*----< create an id string from an instance of T using RTTI >----*/

template<typename T>
std::string Convert<T>::id(const T& t)
{
  return typeid(t).name();
}
          
Template Example Code - TemplatesIntro.cpp
#include "TemplatesIntro.h"

int main()
{
  Title("Demonstrating Templates");
  putLine();

  title("Demonstrating Conversion of numerical types");
  std::cout << "\n  conversion of integer: " << Convert<int>::toString(42);
  std::cout << "\n  conversion of double:  " << Convert<double>::toString(3.1415927);
  putLine();
}
          

User defined types have to provide insertion and extraction operators. You can find an example of that in the TemplateDemo sample code, below. You will find the code for Convert<T> and a TemplatesIntro<T> class that show how Convert<T> is used.

All of the input stream classes: istream, ifstream, and istringstream, provide extraction operators and all of the output stream classes: ostream, ofstream, and ostringstream, provide insertion operators that convert primitive types (integral types, floating types) to and from strings.

We are using the conversion provided by the std::istringstream class extraction operator>> in Check<T>::fromString(const std::string& str), and by the std::ostringstream class insertion operator<< in Check<T>::toString(const T& t).

You can do the same for your user-defined classes, simply by overloading those operators to save and retrieve the class's state. For classes with complex state you may need to save to an XML string for insertion, and parse the string for extraction. The XmlDocument package will be helpful for that.

Template Stack Example

Templates Presentation

More Templates Code Examples:

References:

CST strip