Simple Template Programming

Andy Balaam
artificialworlds.net/blog

Contents

C++ Templates

C++ templates allow you to write a single piece of code that works for multiple types.

For example:

mylist<int> a;
a.add( 3 );     // ok
a.add( "foo" ); // compile error

Not Java Generics

Not Java Generics

Also, C++ templates don't only use types:

// Make something that adds 3
adder<3> add3;

// This prints 5
cout << add3.doit( 2 ) <<  endl;

Not Java Generics

Also, C++ templates do specialisation.

Not Java Generics

Also, C++ templates do specialisation.

Which is seriously cool.

Syntax

Class declaration:

template<int ToAdd>
class adder
{
public:
    int doit( int x );
};

Syntax

Class definition:

template<int ToAdd>
int adder<ToAdd>::doit( int x )
{
    return ToAdd + x;
}

Syntax

Specialisation:

template<>
class adder<0> {
public:
    int doit( int x );
};

template<>
int adder<0>::doit( int x ) {
    return x; // optimised!
}

pow() at compile time

Let's calculate some things at compile time:

cout << Pow<2, 16>::value << endl;
cout << Pow<3,  3>::value << endl;

This prints:

65536
27

pow() at compile time

Don't believe me?

// h.cpp
cout << 65536 << endl;
cout << 27    << endl;

// c.cpp
cout << Pow<2, 16>::value << endl;
cout << Pow<3,  3>::value << endl;

pow() at compile time

Don't believe me?

$ g++ -S h.cpp
$ g++ -S c.cpp

$ diff -U 0 h.s c.s
--- h.s 2014-03-06
+++ c.s  2014-03-06
@@ -1 +1 @@
-   .file   "h.cpp"
+   .file   "c.cpp"

pow() at compile time

template<int B, int E>
class Pow
{
public:
    static const int value =
        B * Pow<B, E-1>::value;
};

pow() at compile time

template<int B>
class Pow<B, 0>
{
public:
    static const int value = 1;
};

Fibonacci

#define NUM 40

int answer[NUM];
Fib<NUM> ctf( answer );

Fibonacci

void fibimpl(
    int* answer, int n1, int n2, int num )
{
    if ( num > -1 ) {
        answer[num] = n1;
        fibimpl(
            answer, n2, n1 + n2, num - 1 );
    }
}

void fib( int* answer, int num )
{
    fibimpl( answer, 1, 1, num - 1 );
}

Fibonacci

template<int Num>
class Fib
{
public:
    Fib( int* answer );
};

template<int Num>
Fib<Num>::Fib( int* answer )
{
    FibImpl<1, 1, Num-1> impl( answer );
}

Fibonacci

template<int N1, int N2, int Num>
class FibImpl :
    public FibImpl<N2, N1 + N2, Num - 1>
{
public:
    FibImpl( int* answer );
};

template<int N1, int N2>
class FibImpl<N1, N2, -1>
{
public:
    FibImpl( int* answer );
};

Fibonacci

template<int N1, int N2, int Num>
FibImpl<N1, N2, Num>::FibImpl( int* answer )
: FibImpl<N2, N1 + N2, Num - 1>( answer )
{
    answer[Num] = N1;
}

template<int N1, int N2>
FibImpl<N1, N2, -1>::FibImpl( int* answer )
{
}

Fibonacci

$ g++ -S compile-time-fib.cpp

$ grep 4181 compile-time-fib.s | grep movq

    movq    $4181, (%rax)

$ grep 1597 compile-time-fib.s | grep movq

    movq    $1597, (%rax)

More info

Videos youtube.com/user/ajbalaam
Twitter @andybalaam
Blog artificialworlds.net/blog
Projects artificialworlds.net