C++, Templates

Templating rocks. But it seems to be something that’s missed out when people are learning C++. It’s like they learn about syntax, variables, structs, classes, pointers – and then they’re off, and forget to keep learning. This is despite using them all the time without realizing it (the std library). Well here’s where you learn.

So imagine a simple maths function, Approach.

    float Approach( float fCurrent, float fTarget, float fDelta )

    {

        if ( fCurrent < fTarget )

        {

            fCurrent += fDelta;

            if ( fCurrent > fTarget ) return fTarget;

        }

        else if ( fCurrent > fTarget )

        {

            fCurrent -= fDelta;

            if ( fCurrent < fTarget ) return fTarget;

        }

 

        return fCurrent;

    }

Takes a starter float, a target float and a delta.. and approaches the number by delta units. Simple right?

But what if you want the same thing for an int? Then you’d probably end up writing it again, called ApproachInt with int. (Yeah more likely you’d just cast them sharrap).

Well if you code it as a template function you don’t have to worry about that.

    template <typename T, typename T2>

    inline T Approach( T fCurrent, T fTarget, T2 fDelta )

    {

        if ( fCurrent < fTarget )

        {

            fCurrent += fDelta;

            if ( fCurrent > fTarget ) return fTarget;

        }

        else if ( fCurrent > fTarget )

        {

            fCurrent -= fDelta;

            if ( fCurrent < fTarget ) return fTarget;

        }

 

        return fCurrent;

    }

Now it can be used with any type! I won’t bother explaining the code since it’s pretty simple to work out.

One thing that might confuse you – why did I add T2. Why use 2 different types? Shouldn’t they all be the same? Well I was forward planning. This is used for vectors too. But since that template won’t translate directly to a Vector.. we have to specialize it.. like so:

    template<> inline Vector Approach<Vector, float>( Vector fCurrent, Vector fTarget, float fDelta )

    {

        Vector vDelta = fTargetfCurrent;

        float fDist = vDelta.Length();

 

        if ( fDist < fDelta )

        {

            return fTarget;

        }

 

        return fCurrent + vDelta.GetNormal() * fDelta;

    }

Now whenever you call Approach( vector, vector, float ) it will use this function, and give us the expected results.

This works for a lot of things. I used to be a total Macro freak. Everything I coded was a macro. Then I found out that Macros Suck. For example, a Swap function.

    #define Swap( typenme, x, y ) { typenme t = x; x = y; y = t; }

Becomes

    template <class T>

    void Swap( T &var1, T &var2 )

    {

        T var_temp = var1;

        var1 = var2;

        var2 = var_temp;

    }

You’re probably thinking – how the fuck is that better. Look at it! It’s a mess! Well I’ve come to learn that you want to try to avoid macros as much as possible. Say you start using some 3rd party API and one of the functions on one of the classes is called Swap – you are now fucked. Because your macro will replace it, everywhere in your code. Now you got a big un-compilable mess.

Using a template isn’t going to do that. You could even keep it in a namespace or a class – impossible with a macro. You could specialize it too – maybe when you Swap a certain type or class you want to do something different. Well now you can.

I hope this has opened some eyes to Templates. Have a think about it next time you’re coding a class with SetFloat, SetInt, SetChar members. There’s a lot you can do (or avoid doing) with them.

Here’s some more reading.