Valid
	XHTML 1.1! Valid CSS!
Created 2003-12-01   Modified 2009-04-11
Chelton Evans

proj Template Notes home

Determining Element Types
Nontype Template Parameters
error: too few template-parameter-lists
References
TODO

The three contradictions

All Implementation in one file

Write template classes in headers. Sadly the implementation can't be separated from the interface and after 10 years the compilers still can't do it.

When working with templates I often get caught on simple things like putting an enum type in a templated class and initializing a static variable with this type. The error messages are a hint and their best information is their location. One solution I found was to include the source within the class. When it works here I know that my error is in syntax and I can move the code outside the class. Often I find it easier to compile code within the class than outside.

Template specialization by stealth

Imagine that you have a class with a template parameter that you wish to treat differently with different function signatures in different contexts. By using a templated member function for each different case you can do whatever you like inside the function as the compiler only checks when the function is instantiated.

For example I had a SurfRectContainer<S,T> class where S was the surface. Construction of the surface was separated with calls to template< class F >     void construct( F& function ); , void construct_uv( F& function ) , void construct_z( F& function ) each interpreting the surface differently.

Inheritance

Inheritance is fundamental to building a type. For the storing of objects in a container they need a base type to iterate over the container. A virtual function is needed as a public interface for the type.

By inheriting a scope is introduced into the subclass. The base class is the generalization. Adding new types of vector elements is easy if the elements derive from the same type.

Runtime decisions are possible.

Functional Objects - a horizontal relationship

Visually inheritance is a vertical relationship between classes. Overloading is also a vertical relationship. Horizontal relationships between classes are also possible. Where the classes need share no relationships to each other but their name and signature.

This horizontal relationships are called functional objects. However almost always the name has been abstracted out which requires more C++ machinery and is limited generally to one such abstraction per class. Lets classify functional objects as having limited horizontal relationships. And call this vertical relationship horizontal overloading .

By contrast full horizontal overloading does not restrict the name and signatures. Templates are needed as the decision making is compile time bound.

Its been my experience that horizontal overloading is much harder to code for. In contrast with vertical overloading which is incredibly useful and easy - I programmed with them in OO before I used virtual functions, though that was long ago.

Horizontal overloading requires templates and more importantly a full understanding of dependencies at compile time. For some generic math library stuff I gave up.

However is this my inexperience in doing this? If I practiced it more would vertical overloading become as natural as overloading? Since no one around me did this it is an open question, I guess I will just have to code it a bit.

Minimizing template types

Imagine a truly templated container with any type possible. In C++ there would be no way to generically iterate over it. Now imagine infinite preprocessing abilities then say if we wanted to apply a functional object operator void ()(int,int) across the container the computer manually generated and inserted each call line by line.

The problem is trivial with virtual functions, a runtime decision. By reducing all the different types to one, they can be put in a container and by virtual function on the operator the right function will be called.

An alternative to virtual functions is to have one unique function that can be configured - say at construction time.

Inheritance could be used to configure the base class when virtual function calls are not used, but the function call in the base class must be unique, hence only the data members can be modified. This makes the non-virtual functions an extensible system.

A generic container, a derived class that is templated

By having a non-templated class as the base class and interface, other types can be derived hiding their data types. For example imagine you wanted a container of multiple data types. If they were wanted for a particular operation specify this in a base class. Have a derived class thats templated and forwards the operation to the templated data. This is the mother of big OO techniques in C++ because it realizes different data types in the one structure. It can be built into the class or as just described be an added wrapper. The public operation in the base class is virtual. And usually virtual destructors would be implemented for memory management.

Writing Templated Code

I often write non-templated code before templated code. By writing for a specific type I get a feel for the problem, often I don't know how I am solving something.

Generally code that is to be templated is a higher standard than non-templated code. I found myself forced to better separate problems between classes. The aim is to minimize template parameters to be only the essential parameters. This leads to classes which use templated classes also having to be templated, if you can better separate the functionality between the classes maybe you don't have to template some classes, or minimize the use of templates.

This leads me to a golden rule that my first C++ boss Claus had and that was a class should have no more than 5 functions. Its a challenging rule and often he would break it to 10. In designing templated solutions I can see good uses for small classes that break down the job into bits. Its another way of thinking about problems.

Why use vertical overloading

STL uses functional objects which are a specific type of vertical overloading. And its fast. The reason is that the compiler can nut out a direct function call at compile time. Apparently even with in lining (where the compiler has access to all the code) the faster machines go the greater the gap between direct calls and in lining. What this means in practice is that vertical overloading results in the fastest code, and may go faster on a better machine.

Nontype Template Parameters

These are template arguments which are not classes, for example int.

Do not use them in general. Unless you are doing something on specialized hardware or other specialized purpose. The classic example of its use is to build a fixed size stack or array. This is almost always the wrong thing to do. Firstly why not just allocate the memory at run time. Secondly a template fixes the type so other templates of different parameters can not easily interact. In general a templated problem requires a templated solution, so if you start using templates all your subsequent work will use them too.

For a practical example I designed a DE solver with fixed size array, as soon as someone hit me with a problem that needed the solver to have its dimensions determined at run time it no longer worked. Further the effort that I put into the design was beyond the normal even by programmers standards so all the effort in the design was lost for that moment in times perspective. So think very carefully before putting in non template parameters.

Determining Element Types

Using a template class to pass a type to another template class. Very useful.

template< typename FN, typename XI, typename T >
class explore 
{
public:

  typedef T Ttype;

...
};

template< typename EXP >
class pattern
{
...
  cirbuffarr< typename EXP::Ttype > xi0;
...
};

void main()
{
  ...
  explore<parab2 &,double*,double> g(fn,3);

  pattern< explore<parab2 &,double*,double> > pat(g);

The problem arises when I want further control. Instead of passing the whole g object I just want to pass a reference.

  pattern< explore<parab2 &,double*,double> & > pat(g);

On my compiler this just broke. Since I am serious this is enough justification for me not to use this technique. Fortunately there is a solution where the reference is stripped from the type.

template< typename T >
class typeop 
{
public:

  typedef T Tbare;
};

template< typename T > 
class typeop< T & > 
{
public:

  typedef T Tbare;
}

cirbuffarr< typename typeop<EXP>::Tbare::Ttype > xi0;

See [1].

Overloading typedef

Inline errors with templates

Remember when you compiled your program and if there was an error it broke at that line. Now you may just laugh at my little joke but with inline code it is back to the good old days when the compilers did not do this (there can not be too many of you who remember these days, OO was fun then).

Well fear not because with inlining the stack pointer can get lost/ corrupted. With templates this may become more of a problem.

So in these relatively rare situations - where you happen to be doing something interesting it pays to look around if the compiler decides to break and you observe the situation where you correct an error that is different from the source and inline functions were in the path. If fixing an inline function then solves your problem the error can then be attributed to the inline function, else learn assembler.

error: too few template-parameter-lists

The "too few template-parameter-lists" error occurs when a static template member is not properly defined.

Here is an example of how to define the member zero for a particular instance.

template< typename T, typename D >
class d2halfspace : public partitionspace<T>
{
public:
  
  /** Zero as a small positive number. */
  static D const zero;
...

In a .cpp file the syntax for defining a static member function that had the values realized was to drop the template arguments at the start and put the values in the rest.

template<>
double const d2halfspace<point2<double>,double>::zero = 1E-15;

References

  1. D.Vandevoorde and N.M.Josuttis (2003). C++ Templates The Complete Guide. ISBN 0-201-73484-2. Page 270.

TODO