6.6.

//: C05:Factorial.cpp
// Compile-time computation using templates.
#include <iostream>
using namespace std;

template<int n> struct Factorial {
  enum { val = Factorial<n-1>::val * n };
};

template<> struct Factorial<0> {
  enum { val = 1 };
};

int main() {
  cout << Factorial<12>::val << endl; // 479001600
} ///:~

Listado 6.46. C05/Factorial.cpp


double nums[Factorial<5>::val];
assert(sizeof nums == sizeof(double)*120);

6.6.1.

//: C05:Fibonacci.cpp
#include <iostream>
using namespace std;

template<int n> struct Fib {
  enum { val = Fib<n-1>::val + Fib<n-2>::val };
};

template<> struct Fib<1> { enum { val = 1 }; };

template<> struct Fib<0> { enum { val = 0 }; };

int main() {
  cout << Fib<5>::val << endl;   // 6
  cout << Fib<20>::val << endl;  // 6765
} ///:~

Listado 6.47. C05/Fibonacci.cpp


int val = 1;
while(p--)
   val *= n; -->

int power(int n, int p) {
  return (p == 0) ? 1 : n*power(n, p - 1);
}

//: C05:Power.cpp
#include <iostream>
using namespace std;

template<int N, int P> struct Power {
  enum { val = N * Power<N, P-1>::val };
};

template<int N> struct Power<N, 0> {
  enum { val = 1 };
};

int main() {
  cout << Power<2, 5>::val << endl;  // 32
} ///:~

Listado 6.48. C05/Power.cpp


//: C05:Accumulate.cpp
// Passes a "function" as a parameter at compile time.
#include <iostream>
using namespace std;

// Accumulates the results of F(0)..F(n)
template<int n, template<int> class F> struct Accumulate {
  enum { val = Accumulate<n-1, F>::val + F<n>::val };
};

// The stopping criterion (returns the value F(0))
template<template<int> class F> struct Accumulate<0, F> {
  enum { val = F<0>::val };
};

// Various "functions":
template<int n> struct Identity {
  enum { val = n };
};

template<int n> struct Square {
  enum { val = n*n };
};

template<int n> struct Cube {
  enum { val = n*n*n };
};

int main() {
  cout << Accumulate<4, Identity>::val << endl; // 10
  cout << Accumulate<4, Square>::val << endl;   // 30
  cout << Accumulate<4, Cube>::val << endl;     // 100
} ///:~

Listado 6.49. C05/Accumulate.cpp


void mult(int a[ROWS][COLS], int x[COLS], int y[COLS]) {
  for(int i = 0; i < ROWS; ++i) {
      y[i] = 0;
      for(int j = 0; j < COLS; ++j)
        y[i] += a[i][j]*x[j];
  }
}

void mult(int a[ROWS][COLS], int x[COLS], int y[COLS]) {
  for(int i = 0; i < ROWS; ++i) {
      y[i] = 0;
      for(int j = 0; j < COLS; j += 2)
        y[i] += a[i][j]*x[j] + a[i][j+1]*x[j+1];
  }
}

//: C05:Unroll.cpp
// Unrolls an implicit loop via inlining.
#include <iostream>
using namespace std;

template<int n> inline int power(int m) {
  return power<n-1>(m) * m;
}

template<> inline int power<1>(int m) {
  return m;
}

template<> inline int power<0>(int m) {
  return 1;
}

int main() {
  int m = 4;
  cout << power<3>(m) << endl;
} ///:~

Listado 6.50. C05/Unroll.cpp


//: C05:Max.cpp
#include <iostream>
using namespace std;

template<int n1, int n2> struct Max {
  enum { val = n1 > n2 ? n1 : n2 };
};

int main() {
  cout << Max<10, 20>::val << endl;  // 20
} ///:~

Listado 6.51. C05/Max.cpp


//: C05:Conditionals.cpp
// Uses compile-time conditions to choose code.
#include <iostream>
using namespace std;

template<bool cond> struct Select {};

template<> class Select<true> {
  static void statement1() {
    cout << "This is statement1 executing\n";
  }
public:
  static void f() { statement1(); }
};

template<> class Select<false> {
  static void statement2() {
    cout << "This is statement2 executing\n";
  }
public:
  static void f() { statement2(); }
};

template<bool cond> void execute() {
  Select<cond>::f();
}

int main() {
  execute<sizeof(int) == 4>();
} ///:~

Listado 6.52. C05/Conditionals.cpp


if(cond)
  statement1();
else
  statement2();

//: C05:StaticAssert1.cpp {-xo}
// A simple, compile-time assertion facility

#define STATIC_ASSERT(x) \
  do { typedef int a[(x) ? 1 : -1]; } while(0)

int main() {
  STATIC_ASSERT(sizeof(int) <= sizeof(long)); // Passes
  STATIC_ASSERT(sizeof(double) <= sizeof(int)); // Fails
} ///:~

Listado 6.53. C05/StaticAssert1.cpp


//: C05:StaticAssert2.cpp {-g++}
#include <iostream>
using namespace std;

// A template and a specialization
template<bool> struct StaticCheck {
  StaticCheck(...);
};

template<> struct StaticCheck<false> {};

// The macro (generates a local class)
#define STATIC_CHECK(expr, msg) {             \
  class Error_##msg {};                       \
  sizeof((StaticCheck<expr>(Error_##msg()))); \
}

// Detects narrowing conversions
template<class To, class From> To safe_cast(From from) {
  STATIC_CHECK(sizeof(From) <= sizeof(To),
               NarrowingConversion);
  return reinterpret_cast<To>(from);
}

int main() {
  void* p = 0;
  int i = safe_cast<int>(p);
  cout << "int cast okay" << endl;
  //! char c = safe_cast<char>(p);
} ///:~

Listado 6.54. C05/StaticAssert2.cpp


int i = safe_cast<int>(p);

{                                                   \
   class Error_NarrowingConversion {};              \
   sizeof(StaticCheck<sizeof(void*) <= sizeof(int)> \
           (Error_NarrowingConversion()));          \
}

char c = safe_cast<char>(p);

{                                                    \
   class Error_NarrowingConversion {};               \
   sizeof(StaticCheck<sizeof(void*) <= sizeof(char)> \
           (Error_NarrowingConversion()));           \
}

sizeof(StaticCheck<false>(Error_NarrowingConversion()));
Cannot cast from 'Error_NarrowingConversion' to 'StaticCheck<0>' in function
char safe_cast<char,void *>(void *)