2010-02-10 21:00:55 +01:00
|
|
|
As there are no variables in template meta programming, there is no
|
|
|
|
template equivalent to a tt(for) or tt(while) statement. However, iterations
|
|
|
|
can always be rewritten as recursions. Recursions em(are) supported
|
|
|
|
by templates and so iterations can always be implemented as (tail) recursions.
|
2007-05-13 18:46:51 +02:00
|
|
|
hi(templates: iteration by recursion)
|
|
|
|
|
2010-02-10 21:00:55 +01:00
|
|
|
To implement iterations by (tail) recursion do as follows:
|
2007-05-13 18:46:51 +02:00
|
|
|
itemization(
|
2010-02-10 21:00:55 +01:00
|
|
|
it() define a specialization implementing the end-condition;
|
|
|
|
it() define all other steps using recursion.
|
|
|
|
it() store intermediate values as tt(enum) values.
|
2007-05-13 18:46:51 +02:00
|
|
|
)
|
2010-02-10 21:00:55 +01:00
|
|
|
The compiler selects a more specialized template implementation over a
|
|
|
|
more generic one. By the time the compiler reaches the end-condition the
|
|
|
|
recursion stops since the specialization does not use recursion.
|
2007-05-13 18:46:51 +02:00
|
|
|
|
|
|
|
Most readers will be familiar with the recursive implementation of the
|
2010-02-10 21:00:55 +01:00
|
|
|
mathematical `em(factorial)' operator, commonly represented by the exclamation
|
|
|
|
mark (tt(!)). Factorial tt(n) (so: tt(n!)) returns the successive products
|
|
|
|
tt(n * (n - 1) * (n - 2) * ... * 1), representing the number of ways tt(n)
|
|
|
|
objects can be permuted. Interestingly, the factorial operator is itself
|
|
|
|
usually defined by a em(recursive) definition:
|
2007-05-13 18:46:51 +02:00
|
|
|
verb(
|
2007-06-14 12:31:01 +02:00
|
|
|
n! = (n == 0) ?
|
2007-05-13 18:46:51 +02:00
|
|
|
1
|
|
|
|
:
|
|
|
|
n * (n - 1)!
|
|
|
|
)
|
2008-03-17 20:37:00 +01:00
|
|
|
To compute tt(n!) from a template, a template tt(Factorial) can be defined
|
2010-02-10 21:00:55 +01:00
|
|
|
using an tt(int n) template non-type parameter. A specialization is defined
|
2007-05-13 18:46:51 +02:00
|
|
|
for the case tt(n == 0). The generic implementation uses recursion according
|
2010-02-10 21:00:55 +01:00
|
|
|
to the factorial definition. Furthermore, the tt(Factorial) template defines
|
|
|
|
an tt(enum) value `tt(value)' containing its factorial value. Here is the
|
2007-05-13 18:46:51 +02:00
|
|
|
generic definition:
|
|
|
|
verb(
|
|
|
|
template <int n>
|
2008-03-17 20:37:00 +01:00
|
|
|
struct Factorial
|
2007-05-13 18:46:51 +02:00
|
|
|
{
|
2008-03-17 20:37:00 +01:00
|
|
|
enum { value = n * Factorial<n - 1>::value };
|
2007-05-13 18:46:51 +02:00
|
|
|
};
|
|
|
|
)
|
2010-02-10 21:00:55 +01:00
|
|
|
Note how the expression assigning a value to `tt(value)' uses constant
|
|
|
|
values that can be determined by the compiler. The value n is provided, and
|
|
|
|
tt(Factorial<n - 1>) is computed using em(template meta
|
|
|
|
programming). tt(Factorial<n-1>) in turn results in value that can be
|
|
|
|
determined by the compiler (em(viz.)
|
|
|
|
tt(Factorial<n-1>::value)). tt(Factorial<n-1>::value) represents the tt(value)
|
|
|
|
defined by the em(type) tt(Factorial<n - 1>). It is em(not) the value returned
|
|
|
|
by an em(object) of that type. There are no objects here but merely values
|
|
|
|
defined by types.
|
2007-05-13 18:46:51 +02:00
|
|
|
|
2010-02-10 21:00:55 +01:00
|
|
|
The recursion ends in a specialization. The compiler will select the
|
|
|
|
specialization (provided for the terminating value 0) instead of the generic
|
|
|
|
implementation whenever possible. Here is the specialization's implementation:
|
2007-05-13 18:46:51 +02:00
|
|
|
verb(
|
|
|
|
template <>
|
2008-03-17 20:37:00 +01:00
|
|
|
struct Factorial<0>
|
2007-05-13 18:46:51 +02:00
|
|
|
{
|
|
|
|
enum { value = 1 };
|
|
|
|
};
|
|
|
|
)
|
2008-03-17 20:37:00 +01:00
|
|
|
The tt(Factorial) template can be used to determine, compile time, the
|
2007-05-13 18:46:51 +02:00
|
|
|
number of permutations of a fixed number of objects. E.g.,
|
|
|
|
verb(
|
|
|
|
int main()
|
|
|
|
{
|
2007-06-14 12:31:01 +02:00
|
|
|
cout << "The number of permutations of 5 objects = " <<
|
2008-03-17 20:37:00 +01:00
|
|
|
Factorial<5>::value << "\n";
|
2007-05-13 18:46:51 +02:00
|
|
|
}
|
|
|
|
)
|
2010-08-25 15:50:41 +02:00
|
|
|
Once again, tt(Factorial<5>::value) is em(not) evaluated at run-time, but
|
|
|
|
at compile-time. The run-time equivalent of the above tt(cout) statement is,
|
2010-02-10 21:00:55 +01:00
|
|
|
therefore:
|
2007-05-13 18:46:51 +02:00
|
|
|
verb(
|
|
|
|
int main()
|
|
|
|
{
|
2007-06-14 12:31:01 +02:00
|
|
|
cout << "The number of permutations of 5 objects = " <<
|
2007-05-13 18:46:51 +02:00
|
|
|
120 << "\n";
|
|
|
|
}
|
|
|
|
)
|