Introduction
The magic of the main function
#include <cmath>#include <iostream>
#include "simpsons_rule.h"
const double PI = 4.0 * atan(1.0); // PI number
double F(double x) {return cos(x);} // Integrand
extern const double A = 0.0; // Left boundary
extern const double B = PI / 2.0; // Right boundary
int main(int argn, char *argc[])
{
// Application of the Simpson's rule.
// F is integrated from A to B with a partition size of 100.
std::cout << simpsons_rule<F, A, B, 100>::result << std::endl;
return 0;
}
Implementing the factorial (1)
#ifndef FACTORIAL_H
#define FACTORIAL_H
#include <cstddef>
// [1]
template <size_t N>
struct factorial
{
static const size_t result;
};
// [2]
template <size_t N>
const size_t factorial<N>::result = N * factorial<N - 1>::result;
// [3]
template <>
struct factorial<1>
{
static const size_t result;
};
// [4]
const size_t factorial<1>::result = 1;
#endif
std::cout << factorial<5>::result << std::endl;
factorial<5>::result = 5 * factorial<4>::result
factorial<4>::result = 4 * factorial<3>::result
factorial<5>::result = 5 * 4 * 3 * 2 * factorial<1>::result
factorial<5>::result = 5 * 4 * 3 * 2 * 1
Implementing the factorial (2)
#ifndef FACTORIAL_H
#define FACTORIAL_H
#include <cstddef>
// With the following definition, factorial<N> is recursively
// resolved as factorial<N, 1, 1, 2, 3, ..., N>.
template <size_t N, size_t M = N + 1, size_t... Indices>
struct factorial : public factorial<N, M - 1, M – 1, Indices...> // [1]
{};
// Thus, in the following specialization, Indices... corresponds
// to the sequence: {1, 2, 3, ..., N}.
template <size_t N, size_t... Indices>
struct factorial<N, 1, Indices...> // [2]
{
static const size_t result;
};
// The sequence above is split into the First index {1} plus
// the Rest...: {2, 3, ..., N}.
template <size_t N, size_t First, size_t... Rest>
struct factorial<N, 1, First, Rest...> // [3]
{
static const size_t result;
};
// The indices in the sequence are recursively evaluated.
template <size_t N, size_t First, size_t... Rest> // [4]
const size_t factorial<N, 1, First, Rest...>::result =
First * factorial<N, 1, Rest...>::result; // Second factor evaluated at [2]
// And finally, this specialization matches the case in
// which all indices have been consumed.
template <size_t N> // [5]
struct factorial<N, 1>
{
static const size_t result;
};
template <size_t N> // [6]
const size_t factorial<N, 1>::result = 1;
#endif
factorial<5> -> factorial<5, 5, 5>, with Indices… empty.
factorial<5, 5, 5> -> factorial<5, 4, 4, 5>, with Indices… = {5}.
factorial<5, 4, 4, 5> -> factorial<5, 3, 3, 4, 5>, with Indices… = {4, 5}.
factorial<5, 3, 3, 4, 5> -> factorial<5, 2, 2, 3, 4, 5>, with Indices… = {3, 4, 5}.
factorial<5, 2, 2, 3, 4, 5> -> factorial<5, 1, 1, 2, 3, 4, 5>, with Indices… = {2, 3, 4, 5}.
An esoteric Fibonacci sequence
The trapezoidal rule



// trapezoidal_rule<> integrates a function F(x) between
// boundaries A and B with a partition size of N by means
// of the trapezoidal rule. See:
//
// http://en.wikipedia.org/wiki/Trapezoidal_rule
//
// Computations are intended to be done at compile time.
//
// Legend:
// F: integrand (function to be integrated)
// A: left boundary
// B: right boundary
// N: partition size
// I: initially equal to N - 1. It is then
// recursively decreased down to 0.
#ifndef TRAPEZOIDAL_RULE_H
#define TRAPEZOIDAL_RULE_H
#include <cstddef>
typedef double (*integrand_type)(double);
typedef const double& boundary_type;
//
// Class: summation<>
//
template <integrand_type F, boundary_type A, boundary_type B, size_t N, size_t I = N - 1>
struct summation
{
static const double result;
};
template <integrand_type F, boundary_type A, boundary_type B, size_t N, size_t I>
const double summation<F, A, B, N, I>::result =
F(A + I * (B - A) / N) + summation<F, A, B, N, I - 1>::result;
template <integrand_type F, boundary_type A, boundary_type B, size_t N>
struct summation<F, A, B, N, 0>
{
static const double result;
};
template <integrand_type F, boundary_type A, boundary_type B, size_t N>
const double summation<F, A, B, N, 0>::result = 0.0;
//
// Class: trapezoidal_rule<>
//
template <integrand_type F, boundary_type A, boundary_type B, size_t N>
struct trapezoidal_rule
{
static const double result;
};
template <integrand_type F, boundary_type A, boundary_type B, size_t N>
const double trapezoidal_rule<F, A, B, N>::result =
(B - A) / N * (0.5 * (F(A) + F(B)) + summation<F, A, B, N>::result);
#endif
// trapezoidal_rule_2<> yields the same result as trapezoidal_rule<>
// but it uses an indices unrolling technique instead of recursion.
//
// Legend:
// F: integrand (function to be integrated)
// A: left boundary
// B: right boundary
// N: partition size
// M: initially equal to N. Later it is unrolled
// into the sequence: {1, 1, 2, 3, ..., N - 1}.
#ifndef TRAPEZOIDAL_RULE_2_H
#define TRAPEZOIDAL_RULE_2_H
#include <cstddef>
typedef double (*integrand_type)(double);
typedef const double& boundary_type;
//
// Class: summation_<>
//
// With the following definition, summation_<F, A, B, N> is recursively
// resolved as summation_<F, A, B, N, 1, 1, 2, 3, ..., N - 1>.
template <integrand_type F, boundary_type A, boundary_type B, size_t N, size_t M = N, size_t... Indices>
struct summation_ : public summation_<F, A, B, N, M - 1, M - 1, Indices...> // [1]
{};
// Thus, in the following specialization, Indices... corresponds to the
// sequence: {1, 2, 3, ..., N - 1}.
template <integrand_type F, boundary_type A, boundary_type B, size_t N, size_t... Indices>
struct summation_<F, A, B, N, 1, Indices...> // [2]
{
static const double result;
};
// The sequence above is split into the First index {1} plus the Rest...: {2, 3, ..., N - 1}.
template <integrand_type F, boundary_type A, boundary_type B, size_t N, size_t First, size_t... Rest>
struct summation_<F, A, B, N, 1, First, Rest...> // [3]
{
static const double result;
};
// The indices in the sequence are recursively evaluated.
template <integrand_type F, boundary_type A, boundary_type B, size_t N, size_t First, size_t... Rest>
const double summation_<F, A, B, N, 1, First, Rest...>::result =
F(A + First * (B - A) / N) + summation_<F, A, B, N, 1, Rest...>::result; // Second addend evaluated at [2]
// And finally, this specialization matches the case in
// which all indices have been consumed.
template <integrand_type F, boundary_type A, boundary_type B, size_t N>
struct summation_<F, A, B, N, 1>
{
static const double result;
};
template <integrand_type F, boundary_type A, boundary_type B, size_t N>
const double summation_<F, A, B, N, 1>::result = 0.0;
//
// Class: trapezoidal_rule_2<>
//
template <integrand_type F, boundary_type A, boundary_type B, size_t N>
struct trapezoidal_rule_2
{
static const double result;
};
template <integrand_type F, boundary_type A, boundary_type B, size_t N>
const double trapezoidal_rule_2<F, A, B, N>::result =
(B - A) / N * (0.5 * (F(A) + F(B)) + summation_<F, A, B, N>::result);
#endif
Source code
References
- Trapezoidal rule. (http://en.wikipedia.org/wiki/Trapezoidal_rule).
- Simpson’s rule. (http://en.wikipedia.org/wiki/Simpson's_rule).
- Compile time function execution. (http://en.wikipedia.org/wiki/Compile_time_function_execution).
- “Unpacking” a tuple to call a matching function pointer. (http://stackoverflow.com/questions/7858817/unpacking-a-tuple-to-call-a-matching-function-pointer).





