//: 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);
//: 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 *)