how to use template metaprogramming to write functional code in c++
You might be approaching the subject from a wrong angle. Metaprogramming involves writing instructions for how to write programs, reaching a level of abstraction beyond normal programming. (For more information, I recommend A: What is metaprogramming? by ShuggyCoUk.)
When you write a class template, you are not defining a class. Rather, you write instructions that tell the compiler how to write variations of a class definition that are adapted to different scenarios. Read that sentence again, but with the recognition that "instructions for a computer" means "a program" and that "a class definition" is part of a program. That sentence basically says that writing a (class) template is writing a program that writes (part of) a program. Programs that write programs is the "meta" aspect of "metaprogramming".
Now think about the life cycle of a typical C++ program. Source code is written, the program is converted by a compiler to an executable, then the executable is run. Write, compile, then run, as three disjoint steps. Let's assume that adding steps to this sequence is not an option. (Other languages may choose a different approach.) If the program produced by metaprogramming is to become executable, that program better exist before the compiler is done.
That is the key aspect of metaprogramming as it relates to this question. Metaprograms are written at the same time as other code, and the resulting program is run at the same times as normal. The conversion from "metaprogram" to "program" occurs during compilation. The metaprogram is "executed" by the compiler to produce program pieces that are then incorporated into the rest of your code. Metaprogramming targets the compiler. All inputs to metaprograms must be known by the compiler, hence known at the time of compilation.
The values of most variables are not known to the compiler, as the values often change while the program runs. These values cannot be used as inputs to C++ metaprogramming. The exceptions are variables marked as constexpr
, a marking that means the value is knowable by the compiler. A constexpr
variable can be used as a template argument; other variables cannot.
Specific case: Fibonacci
Your Fib
example tells the compiler how to define each member of a family of struct
s. For any triple of int
s, the compiler can apply your template to generate the definition of the corresponding struct
. There happens to be a way to get certain Fibonacci numbers from certain members of this family, but at its core, you have simply written the instructions for defining the members of this family.
The compiler is not going to create every possible member of this family. (Even with the smallest allowable int
implementation, there are over 200 trillion members of this family.) Rather, the compiler will create just those members that it knows it needs. You can get the compiler to produce any specific Fibonacci number (up to certain implementation limits), but it will not produce every Fibonacci number (even subject to the limitation that the number be small enough to fit in an int
).
Metaprogramming is useful for calculating based on values known at compile-time, but to calculate based on run-time values, you need a run-time function. Use the right tool for the job.