Template metaprogramming is tricky because you have to keep track of two layers of abstraction.
The usual layer: code you write gets compiled and stored for later execution.
Template stuff: you're programming the compiler
For example, you may want to average two numbers. You write a function:
1 2 3 4
|
double average( double a, double b )
{
return (a + b) / 2;
}
|
It works great. But then you go and write code using complex numbers. You have to rewrite the function:
1 2 3 4
|
std::complex <double> average( std::complex <double> a, std::complex <double> b )
{
return (a + b) / 2;
}
|
Oh, then you have some calculations that need to take advantage of the increased precision your compiler (may) give you if you use
long doubles. More rewrites:
1 2 3 4 5 6 7 8 9
|
long double average( long double a, long double b )
{
return (a + b) / 2;
}
std::complex <long double> average( std::complex <long double> a, std::complex <long double> b )
{
return (a + b) / 2;
}
|
As you can see, we are still only writing normal, gets compiled, stored, and executed later stuff. But it is a lot of stuff just to do one thing:
return (a + b) / 2;
(That one thing need not be so simple. It could be very complex, which makes the rewriting even more obnoxious.) All this leads to duplicate code that is hard to maintain.
What if we could tell the compiler to do it for us?
Yes, that is the purpose of templates. We create a cookie-cutter
template for something for the compiler, so when we need a function that does that thing to a
double or an
int, we just use it and the compiler writes and compiles the code for us.
1 2 3 4 5
|
template <typename T>
T average( T a, T b )
{
return (a + b) / 2;
}
|
Now to your question. The important point of all this template stuff is that
everything must be resolved before your program gets executed.
This makes sense. You cannot create and compile code on-the-fly while your program is running, since the compiler is not running as part of your program.
Which means that things like
int a = 7;
cannot be used to resolve template functions, because
a is a
variable — your program can change it at any time. But your program cannot change what has been compiled to match it.
In short, you need to change the structure of your program to not rely on runtime values. Make whatever you are trying to change into an argument to the function.
Hope this helps.