This was a program I wrote a while ago (2003) to demonstrate what can be done with template metaprogramming in C++. It’s based on Todd Veldhuilzen’s article [1] on template metaprograms. Basically, a template metaprogram is something that the compiler runs to generate more code. It’s a way of getting the compiler to do the work for you. Additionally, the template language is Turing complete which basically means that if a problem is computable, then the language can be used to write an algorithm for it.
Counting days from the 1st March 1984.
<!-- Generator: GNU source-highlight 3.1.4 by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite -->
#include <iostream>
using namespace std;
#define ENDGUARD(Value) (Value)
#define GUARD(Condition, Value) (Condition) ? (Value) :
class DaysPerMonth
{
public:
static const int Jan = 31;
static const int Feb = 28;
static const int Mar = 31;
static const int Apr = 30;
static const int May = 31;
static const int Jun = 30;
static const int Jul = 31;
static const int Aug = 31;
static const int Sep = 30;
static const int Oct = 31;
static const int Nov = 30;
static const int Dec = 31;
};
template<int Month>
class SelectMonth;
template<int Month>
class SelectMonth
{
public:
enum
{
value = GUARD(Month == 1, DaysPerMonth::Jan)
GUARD(Month == 2, DaysPerMonth::Feb)
GUARD(Month == 3, DaysPerMonth::Mar)
GUARD(Month == 4, DaysPerMonth::Apr)
GUARD(Month == 5, DaysPerMonth::May)
GUARD(Month == 6, DaysPerMonth::Jun)
GUARD(Month == 7, DaysPerMonth::Jul)
GUARD(Month == 8, DaysPerMonth::Aug)
GUARD(Month == 9, DaysPerMonth::Sep)
GUARD(Month == 10, DaysPerMonth::Oct)
GUARD(Month == 11, DaysPerMonth::Nov)
GUARD(Month == 12, DaysPerMonth::Dec)
ENDGUARD(0)
};
};
template<int Year>
class IsLeapYear;
template<int Year>
class IsLeapYear
{
public:
enum { value = (((Year%4 == 0) && (Year%100 != 0)) || (Year%400 == 0)) ? 1 : 0 };
};
template<int Year>
class LeapYearsFrom1984;
template<>
class LeapYearsFrom1984<1985>
{
public:
enum { value = 0 };
};
template<int Year>
class LeapYearsFrom1984
{
public:
enum { value = IsLeapYear<Year>::value + LeapYearsFrom1984<Year-1>::value };
};
template<int Month, int Day>
class IsFeb29;
template<>
class IsFeb29<2, 29>
{
public:
enum { value = 1 };
};
template<int Month, int Day>
class IsFeb29
{
public:
enum { value = 0 };
};
template<int Year, int Month, int Day>
class IsBeforeFeb29;
template<int Year, int Month, int Day>
class IsBeforeFeb29
{
public:
enum { value = (IsLeapYear<Year>::value == 1 && (Month == 1 ||
(Month == 2 && Day < 29))) ? 1 : 0};
};
template<int Month>
class DaysFromYearStart;
template<>
class DaysFromYearStart<0>
{
public:
enum { value = 0 };
};
template<int Month>
class DaysFromYearStart
{
public:
enum { value = SelectMonth<Month>::value + DaysFromYearStart<Month-1>::value };
};
template<int Year>
class DaysInWholeYears;
template<int Year>
class DaysInWholeYears
{
public:
enum { value = 365 * (Year - 1985) };
};
template<int Month>
class DaysFrom1March1984;
template<>
class DaysFrom1March1984<3>
{
public:
enum { value = SelectMonth<3>::value - 1 };
};
template<>
class DaysFrom1March1984<2>
{
public:
enum { value = -1 };
};
template<int Month>
class DaysFrom1March1984
{
public:
enum { value = SelectMonth<Month>::value + DaysFrom1March1984<Month-1>::value };
};
template<int Year, int Month, int Day>
class CountDays;
template<int Month, int Day>
class CountDays<1984, Month, Day>
{
public:
enum
{
value = DaysFrom1March1984<Month-1>::value + Day
};
};
template<int Year, int Month, int Day>
class CountDays
{
public:
enum
{ value = Day + DaysFromYearStart<Month-1>::value +
DaysInWholeYears<Year>::value + DaysFrom1March1984<12>::value +
LeapYearsFrom1984<Year>::value -
IsFeb29<Month, Day>::value - IsBeforeFeb29<Year, Month, Day>::value
};
};
int main()
{
cout << CountDays<1984, 3, 1>::value << endl;
cout << CountDays<1984, 3, 15>::value << endl;
cout << CountDays<1984, 3, 31>::value << endl;
cout << CountDays<1984, 4, 3>::value << endl;
cout << CountDays<1984, 5, 30>::value << endl;
cout << CountDays<1984, 12, 31>::value << endl;
cout << CountDays<1985, 1, 1>::value << endl;
cout << CountDays<1985, 2, 28>::value << endl;
cout << CountDays<1985, 3, 1>::value << endl;
cout << CountDays<1985, 3, 31>::value << endl;
cout << CountDays<1985, 12, 31>::value << endl;
cout << CountDays<1986, 1, 1>::value << endl;
cout << CountDays<1986, 12, 31>::value << endl;
cout << CountDays<1988, 2, 29>::value << endl;
cout << CountDays<1996, 1, 29>::value << endl;
cout << CountDays<1996, 2, 29>::value << endl;
cout << CountDays<1996, 8, 12>::value << endl;
cout << CountDays<2001, 12, 12>::value << endl;
cout << CountDays<2004, 6, 30>::value << endl;
cout << CountDays<2004, 12, 12>::value << endl;
cout << CountDays<2060, 1, 1>::value << endl;
cout << CountDays<2060, 2, 28>::value << endl;
cout << CountDays<2060, 2, 29>::value << endl;
cout << CountDays<2088, 1, 2>::value << endl;
cout << CountDays<2088, 2, 29>::value << endl;
cout << CountDays<2099, 1, 1>::value << endl;
cout << CountDays<2099, 2, 28>::value << endl;
cout << CountDays<2099, 3, 1>::value << endl;
cout << CountDays<2099, 12, 31>::value << endl;
cout << "Press any key to end" << endl;
cin.get();
return 0;
}
References
[1] Todd Veldhuizen, "Using C++ template metaprograms," C++ Report, May 1995